Skip to content

[FS2524] Add Feature Spec as a Bundle Resource - #7364

Open
Daniel114510 wants to merge 16 commits into
mainfrom
fs2524-feature-specs
Open

Daniel114510 wants to merge 16 commits into
mainfrom
fs2524-feature-specs

Conversation

@Daniel114510

@Daniel114510 Daniel114510 commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

Changes

Add feature_specs as a bundle resource type, with a grants field for Unity Catalog privileges on the feature spec.

  • The Feature Engineering API has create, get and delete for feature specs and no update, and every field is IMMUTABLE. Any change therefore recreates the spec, and the adapter has no DoUpdate.
  • A feature spec is a UC function, so grants reuses the grants sub-resource with securable type function. When the spec is recreated, the bundle re-applies its declared grants to the new spec.
  • The fields rename_outputs, default_values and input_bindings of feature spec are compared by key. The string list fields exclude_columns and extra_pip_requirements.requirements are sorted in both the config and the read. This ensures reordering any of these order-free lists plans no change instead of a recreate.
  • bundle deploy and bundle destroy ask for approval before recreating or deleting a feature spec.

Why

Feature specs can only be created through the Python client or the API today. Supporting them in bundles is part of bringing the Feature Engineering API to Declarative Automation Bundles.

Tests

  • Acceptance tests:
    • bundle/resources/feature_specs/basic: create, no-op plan, recreate, destroy
    • bundle/resources/feature_specs/order: which list reorders recreate
    • bundle/resources/feature_specs/remote-delete: spec deleted outside the bundle
    • bundle/resources/grants/feature_specs: grants re-applied after recreate
    • bundle/deployment/bind/feature_spec: bind and unbind an existing spec
    • bundle/resource_deps/implicit_deps_feature_spec: deploys after its catalog and schema
    • bundle/invariant/configs/feature_spec.yml.tmpl: no drift, repeatable delete and destroy
    • bundle/python/feature_specs-support: specs defined and changed in Python
    • experimental/open: lists feature_specs
  • Unit tests:
    • bundle/direct/dresources/feature_spec_test.go: list sorting and matching
    • resource registration tests: feature specs wired like other resources

Daniel114510 and others added 7 commits November 4, 2026 19:24
Dropped when rebasing onto the bot's Update Go SDK to v0.194.0 PR.

Co-authored-by: Isaac <no-reply@databricks.com>
A feature spec has create, get and delete and no update, and every field is
immutable, so any change recreates it. It is a UC function, so its grants go
through the existing grants sub-resource with securable type "function"; on a
recreate the grants node plans an update and re-applies them.

The map-like pair lists (rename_outputs, default_values, input_bindings) are
compared by key, and exclude_columns and the extra pip requirements are sorted
on both sides, so reordering them is not a recreate. features and the lookup
keys stay positional: their order sets the output columns and must match the
table's primary key.

Co-authored-by: Isaac <no-reply@databricks.com>
… FeatureSpec

Replaced by the generator after rebasing onto the SDK bump.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
Also give the fake's feature spec map its own block and shorten the
recreate prompt.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
@github-actions github-actions Bot added DABs DABs related issues PyDABs labels Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Commit: 700f5e0b9 | Workflow run

Regression test report

Selected 14 changed tests (limit=20, 0 not selected)

21 tests: regression=14 unreleased=0 coverage=7 failing=0
test branch main (21db1be) latest (v1.24.0)
TestAccept/bundle/deployment/bind/feature_spec/DMS= ✅ ❌ ❌
TestAccept/bundle/deployment/bind/feature_spec/DMS=true ✅ ❌ ❌
TestAccept/bundle/invariant/continue_293/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl ✅ ✅ ✅
TestAccept/bundle/invariant/delete_idempotent/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN= ✅ ✅ ✅
TestAccept/bundle/invariant/delete_idempotent/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN=1 ✅ ✅ ✅
TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN= ✅ ✅ ✅
TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN=1 ✅ ✅ ✅
TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN= ✅ ✅ ✅
TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN=1 ✅ ✅ ✅
TestAccept/bundle/python/feature_specs-support/DMS=/PYDAB_VERSION=current ✅ ❌ ❌
TestAccept/bundle/python/feature_specs-support/DMS=true/PYDAB_VERSION=current ✅ ❌ ❌
TestAccept/bundle/refschema/DMS= ✅ ❌ ❌
TestAccept/bundle/refschema/DMS=true ✅ ❌ ❌
TestAccept/bundle/resource_deps/implicit_deps_feature_spec/DMS= ✅ ❌ ❌
TestAccept/bundle/resource_deps/implicit_deps_feature_spec/DMS=true ✅ ❌ ❌
TestAccept/bundle/resources/feature_specs/basic/DMS= ✅ ❌ ❌
TestAccept/bundle/resources/feature_specs/order/DMS= ✅ ❌ ❌
TestAccept/bundle/resources/feature_specs/remote-delete/DMS= ✅ ❌ ❌
TestAccept/bundle/resources/feature_specs/uppercase-name/DMS= ✅ ❌ ❌
TestAccept/bundle/resources/grants/feature_specs/DMS= ✅ ❌ ❌
TestAccept/experimental/open ✅ ❌ ❌
TestAccept/bundle/deployment/bind/feature_spec/DMS=: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1345: Diff:
        --- bundle/deployment/bind/feature_spec/output.txt
        +++ /tmp/TestAcceptbundledeploymentbindfeature_specDMS=100050602/002/output.txt
        @@ -16,38 +16,10 @@
         }
         
         >>> [CLI] bundle deployment bind spec1 main.fspec_[UNIQUE_NAME].boundspec --auto-approve
        -Successfully bound feature_spec with an id 'main.fspec_[UNIQUE_NAME].boundspec'
        -Run 'bundle deploy' to deploy changes to your workspace
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        ->>> [CLI] bundle summary
        -Name: test-bind-feature-spec-[UNIQUE_NAME]
        -Target: default
        -Workspace:
        -  User: [USERNAME]
        -  Path: /Workspace/Users/[USERNAME]/.bundle/test-bind-feature-spec-[UNIQUE_NAME]/default
        -Resources:
        -  Feature Specs:
        -    spec1:
        -      Name: main.fspec_[UNIQUE_NAME].boundspec
        -      URL:  [DATABRICKS_URL]/explore/data/functions/main/fspec_[UNIQUE_NAME]/boundspec?w=[WORKSPACE_ID]
        +Error: no such resource: spec1
         
        -=== The bound feature spec matches the config, so there is nothing to change
        ->>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged
        -
        ->>> [CLI] bundle deployment unbind spec1
        -
        ->>> [CLI] bundle summary
        -Name: test-bind-feature-spec-[UNIQUE_NAME]
        -Target: default
        -Workspace:
        -  User: [USERNAME]
        -  Path: /Workspace/Users/[USERNAME]/.bundle/test-bind-feature-spec-[UNIQUE_NAME]/default
        -Resources:
        -  Feature Specs:
        -    spec1:
        -      Name: main.fspec_[UNIQUE_NAME].boundspec
        -      URL:  (not deployed)
        -
        ->>> [CLI] api delete /api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].boundspec
        -{}
        +Exit code: 1
        
    acceptance_test.go:1123: 
        LOG.cleanup: Warning: unknown field: feature_specs
        LOG.cleanup:   at resources
        LOG.cleanup:   in databricks.yml:5:3

latest (v1.24.0): same output as main (21db1be)

TestAccept/bundle/deployment/bind/feature_spec/DMS=true: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1345: Diff:
        --- bundle/deployment/bind/feature_spec/output.txt
        +++ /tmp/TestAcceptbundledeploymentbindfeature_specDMS=true1482177933/002/output.txt
        @@ -16,38 +16,10 @@
         }
         
         >>> [CLI] bundle deployment bind spec1 main.fspec_[UNIQUE_NAME].boundspec --auto-approve
        -Successfully bound feature_spec with an id 'main.fspec_[UNIQUE_NAME].boundspec'
        -Run 'bundle deploy' to deploy changes to your workspace
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        ->>> [CLI] bundle summary
        -Name: test-bind-feature-spec-[UNIQUE_NAME]
        -Target: default
        -Workspace:
        -  User: [USERNAME]
        -  Path: /Workspace/Users/[USERNAME]/.bundle/test-bind-feature-spec-[UNIQUE_NAME]/default
        -Resources:
        -  Feature Specs:
        -    spec1:
        -      Name: main.fspec_[UNIQUE_NAME].boundspec
        -      URL:  [DATABRICKS_URL]/explore/data/functions/main/fspec_[UNIQUE_NAME]/boundspec?w=[WORKSPACE_ID]
        +Error: no such resource: spec1
         
        -=== The bound feature spec matches the config, so there is nothing to change
        ->>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged
        -
        ->>> [CLI] bundle deployment unbind spec1
        -
        ->>> [CLI] bundle summary
        -Name: test-bind-feature-spec-[UNIQUE_NAME]
        -Target: default
        -Workspace:
        -  User: [USERNAME]
        -  Path: /Workspace/Users/[USERNAME]/.bundle/test-bind-feature-spec-[UNIQUE_NAME]/default
        -Resources:
        -  Feature Specs:
        -    spec1:
        -      Name: main.fspec_[UNIQUE_NAME].boundspec
        -      URL:  (not deployed)
        -
        ->>> [CLI] api delete /api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].boundspec
        -{}
        +Exit code: 1
        
    acceptance_test.go:1123: 
        LOG.cleanup: Warning: unknown field: feature_specs
        LOG.cleanup:   at resources
        LOG.cleanup:   in databricks.yml:5:3

latest (v1.24.0): same output as main (21db1be)

TestAccept/bundle/python/feature_specs-support/DMS=/PYDAB_VERSION=current: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1345: Diff:
        --- bundle/python/feature_specs-support/output.txt
        +++ /tmp/TestAcceptbundlepythonfeature_specs-supportDMS=PYDAB_VERSIO912602488/002/output.txt
        @@ -1,5 +1,13 @@
         
         >>> uv run [UV_ARGS] -q [CLI] bundle validate --output json
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:13:3
        +
        +Error: unknown field: feature_specs
        +  at resources
        +  in __generated_by_python__.yml:1:351
        +
         {
           "experimental": {
             "python": {
        @@ -11,47 +19,7 @@
               ]
             }
           },
        -  "resources": {
        -    "feature_specs": {
        -      "my_feature_spec_1": {
        -        "features": [
        -          {
        -            "feature_lookup": {
        -              "feature_names": [
        -                "age"
        -              ],
        -              "lookup_keys": [
        -                "user_id"
        -              ],
        -              "table": "main.default.user_features"
        -            }
        -          }
        -        ],
        -        "grants": [
        -          {
        -            "principal": "account users",
        -            "privileges": [
        -              "EXECUTE"
        -            ]
        -          }
        -        ],
        -        "name": "main.default.my_feature_spec_1_updated"
        -      },
        -      "my_feature_spec_2": {
        -        "extra_pip_requirements": {
        -          "requirements": [
        -            "numpy==2.1.0"
        -          ]
        -        },
        -        "features": [
        -          {
        -            "declarative_feature": {
        -              "feature": "main.default.my_feature"
        -            }
        -          }
        -        ],
        -        "name": "main.default.my_feature_spec_2_updated"
        -      }
        -    }
        -  }
        +  "resources": {}
         }
        +
        +Exit code: 1

latest (v1.24.0): same output as main (21db1be)

TestAccept/bundle/python/feature_specs-support/DMS=true/PYDAB_VERSION=current: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1345: Diff:
        --- bundle/python/feature_specs-support/output.txt
        +++ /tmp/TestAcceptbundlepythonfeature_specs-supportDMS=truePYDAB_VE2258664479/002/output.txt
        @@ -1,5 +1,13 @@
         
         >>> uv run [UV_ARGS] -q [CLI] bundle validate --output json
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:13:3
        +
        +Error: unknown field: feature_specs
        +  at resources
        +  in __generated_by_python__.yml:1:351
        +
         {
           "experimental": {
             "python": {
        @@ -11,47 +19,7 @@
               ]
             }
           },
        -  "resources": {
        -    "feature_specs": {
        -      "my_feature_spec_1": {
        -        "features": [
        -          {
        -            "feature_lookup": {
        -              "feature_names": [
        -                "age"
        -              ],
        -              "lookup_keys": [
        -                "user_id"
        -              ],
        -              "table": "main.default.user_features"
        -            }
        -          }
        -        ],
        -        "grants": [
        -          {
        -            "principal": "account users",
        -            "privileges": [
        -              "EXECUTE"
        -            ]
        -          }
        -        ],
        -        "name": "main.default.my_feature_spec_1_updated"
        -      },
        -      "my_feature_spec_2": {
        -        "extra_pip_requirements": {
        -          "requirements": [
        -            "numpy==2.1.0"
        -          ]
        -        },
        -        "features": [
        -          {
        -            "declarative_feature": {
        -              "feature": "main.default.my_feature"
        -            }
        -          }
        -        ],
        -        "name": "main.default.my_feature_spec_2_updated"
        -      }
        -    }
        -  }
        +  "resources": {}
         }
        +
        +Exit code: 1

latest (v1.24.0): same output as main (21db1be)

TestAccept/bundle/refschema/DMS=: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1316: Missing output file: output/feature_specs.txt

latest (v1.24.0):

acceptance_test.go:1316: Missing output file: output/feature_specs.txt
    acceptance_test.go:1316: Missing output file: output/postgres_data_apis.txt
TestAccept/bundle/refschema/DMS=true: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1316: Missing output file: output/feature_specs.txt

latest (v1.24.0):

acceptance_test.go:1316: Missing output file: output/postgres_data_apis.txt
    acceptance_test.go:1316: Missing output file: output/feature_specs.txt
TestAccept/bundle/resource_deps/implicit_deps_feature_spec/DMS=: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1345: 
        	Error Trace:	/home/runner/work/cli/cli/libs/testdiff/testdiff.go:22
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1345
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1086
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:660
        	Error:      	Not equal: 
        	            	expected: "\n>>> [CLI] bundle validate -t dev -o json\n{\n  \"catalogs\": {\n    \"my_catalog\": {\n      \"name\": \"mycatalog\"\n    }\n  },\n  \"feature_specs\": {\n    \"my_feature_spec\": {\n      \"features\": [\n        {\n          \"feature_lookup\": {\n            \"feature_names\": [\n              \"age\"\n            ],\n            \"lookup_keys\": [\n              \"user_id\"\n            ],\n            \"table\": \"mycatalog.myschema.user_features\"\n          }\n        }\n      ],\n      \"name\": \"${resources.catalogs.my_catalog.name}.${resources.schemas.my_schema.name}.myspec\"\n    }\n  },\n  \"schemas\": {\n    \"my_schema\": {\n      \"catalog_name\": \"${resources.catalogs.my_catalog.name}\",\n      \"name\": \"dev_[USERNAME]_myschema\"\n    }\n  }\n}\n"
        	            	actual  : "\n>>> [CLI] bundle validate -t dev -o json\nWarning: unknown field: feature_specs\n  at resources\n  in databricks.yml:14:3\n\n{\n  \"catalogs\": {\n    \"my_catalog\": {\n      \"name\": \"mycatalog\"\n    }\n  },\n  \"schemas\": {\n    \"my_schema\": {\n      \"catalog_name\": \"${resources.catalogs.my_catalog.name}\",\n      \"name\": \"dev_[USERNAME]_myschema\"\n    }\n  }\n}\n"
        	            	
        	            	Diff:
        	            	--- Expected
        	            	+++ Actual
        	            	@@ -2,2 +2,6 @@
        	            	 >>> [CLI] bundle validate -t dev -o json
        	            	+Warning: unknown field: feature_specs
        	            	+  at resources
        	            	+  in databricks.yml:14:3
        	            	+
        	            	 {
        	            	@@ -6,20 +10,2 @@
        	            	       "name": "mycatalog"
        	            	-    }
        	            	-  },
        	            	-  "feature_specs": {
        	            	-    "my_feature_spec": {
        	            	-      "features": [
        	            	-        {
        	            	-          "feature_lookup": {
        	            	-            "feature_names": [
        	            	-              "age"
        	            	-            ],
        	            	-            "lookup_keys": [
        	            	-              "user_id"
        	            	-            ],
        	            	-            "table": "mycatalog.myschema.user_features"
        	            	-          }
        	            	-        }
        	            	-      ],
        	            	-      "name": "${resources.catalogs.my_catalog.name}.${resources.schemas.my_schema.name}.myspec"
        	            	     }
        	Test:       	TestAccept/bundle/resource_deps/implicit_deps_feature_spec/DMS=
        	Messages:   	bundle/resource_deps/implicit_deps_feature_spec/output.txt vs /tmp/TestAcceptbundleresource_depsimplicit_deps_feature_specDMS=2739777613/002/output.txt

latest (v1.24.0): same output as main (21db1be)

TestAccept/bundle/resource_deps/implicit_deps_feature_spec/DMS=true: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1345: 
        	Error Trace:	/home/runner/work/cli/cli/libs/testdiff/testdiff.go:22
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1345
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1086
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:660
        	Error:      	Not equal: 
        	            	expected: "\n>>> [CLI] bundle validate -t dev -o json\n{\n  \"catalogs\": {\n    \"my_catalog\": {\n      \"name\": \"mycatalog\"\n    }\n  },\n  \"feature_specs\": {\n    \"my_feature_spec\": {\n      \"features\": [\n        {\n          \"feature_lookup\": {\n            \"feature_names\": [\n              \"age\"\n            ],\n            \"lookup_keys\": [\n              \"user_id\"\n            ],\n            \"table\": \"mycatalog.myschema.user_features\"\n          }\n        }\n      ],\n      \"name\": \"${resources.catalogs.my_catalog.name}.${resources.schemas.my_schema.name}.myspec\"\n    }\n  },\n  \"schemas\": {\n    \"my_schema\": {\n      \"catalog_name\": \"${resources.catalogs.my_catalog.name}\",\n      \"name\": \"dev_[USERNAME]_myschema\"\n    }\n  }\n}\n"
        	            	actual  : "\n>>> [CLI] bundle validate -t dev -o json\nWarning: unknown field: feature_specs\n  at resources\n  in databricks.yml:14:3\n\n{\n  \"catalogs\": {\n    \"my_catalog\": {\n      \"name\": \"mycatalog\"\n    }\n  },\n  \"schemas\": {\n    \"my_schema\": {\n      \"catalog_name\": \"${resources.catalogs.my_catalog.name}\",\n      \"name\": \"dev_[USERNAME]_myschema\"\n    }\n  }\n}\n"
        	            	
        	            	Diff:
        	            	--- Expected
        	            	+++ Actual
        	            	@@ -2,2 +2,6 @@
        	            	 >>> [CLI] bundle validate -t dev -o json
        	            	+Warning: unknown field: feature_specs
        	            	+  at resources
        	            	+  in databricks.yml:14:3
        	            	+
        	            	 {
        	            	@@ -6,20 +10,2 @@
        	            	       "name": "mycatalog"
        	            	-    }
        	            	-  },
        	            	-  "feature_specs": {
        	            	-    "my_feature_spec": {
        	            	-      "features": [
        	            	-        {
        	            	-          "feature_lookup": {
        	            	-            "feature_names": [
        	            	-              "age"
        	            	-            ],
        	            	-            "lookup_keys": [
        	            	-              "user_id"
        	            	-            ],
        	            	-            "table": "mycatalog.myschema.user_features"
        	            	-          }
        	            	-        }
        	            	-      ],
        	            	-      "name": "${resources.catalogs.my_catalog.name}.${resources.schemas.my_schema.name}.myspec"
        	            	     }
        	Test:       	TestAccept/bundle/resource_deps/implicit_deps_feature_spec/DMS=true
        	Messages:   	bundle/resource_deps/implicit_deps_feature_spec/output.txt vs /tmp/TestAcceptbundleresource_depsimplicit_deps_feature_specDMS=t292051329/002/output.txt

latest (v1.24.0): same output as main (21db1be)

TestAccept/bundle/resources/feature_specs/basic/DMS=: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1345: Diff:
        --- bundle/resources/feature_specs/basic/output.txt
        +++ /tmp/TestAcceptbundleresourcesfeature_specsbasicDMS=1521882314/002/output.txt
        @@ -8,174 +8,30 @@
         
         === Initial summary before deploy
         >>> [CLI] bundle summary -o json
        -{
        -  "extra_pip_requirements": {
        -    "requirements": [
        -      "numpy==2.1.0"
        -    ]
        -  },
        -  "features": [
        -    {
        -      "feature_lookup": {
        -        "feature_names": [
        -          "age",
        -          "country"
        -        ],
        -        "lookup_keys": [
        -          "user_id"
        -        ],
        -        "table": "main.fspec_[UNIQUE_NAME].user_features"
        -      }
        -    },
        -    {
        -      "feature_function": {
        -        "input_bindings": [
        -          {
        -            "bound_feature": "age",
        -            "parameter": "x"
        -          }
        -        ],
        -        "output": "score",
        -        "udf": "main.fspec_[UNIQUE_NAME].score"
        -      }
        -    }
        -  ],
        -  "modified_status": "created",
        -  "name": "[SPEC1_ID]"
        -}
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        +null
        +
         >>> [CLI] bundle deploy
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
        +
         Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-basic-[UNIQUE_NAME]/default/files...
        -Created feature_specs.spec1
         Files: 2 uploaded, 0 deleted
        -Resources: 1 created, 0 changed, 0 deleted, 0 unchanged
        +Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        +Traceback (most recent call last):
        +  File "[TESTROOT]/bin/replace_ids.py", line 68, in <module>
        +    main()
        +    ~~~~^^
        +  File "[TESTROOT]/bin/replace_ids.py", line 63, in main
        +    for name, id in it:
        +                    ^^
        +  File "[TESTROOT]/bin/replace_ids.py", line 18, in iter_ids_terraform
        +    raw = open(filename).read()
        +          ~~~~^^^^^^^^^^
        +FileNotFoundError: [Errno 2] No such file or directory: '.databricks/bundle/default/terraform/terraform.tfstate'
         
        ->>> print_requests.py //feature-engineering
        -{
        -  "method": "POST",
        -  "path": "/api/2.0/feature-engineering/feature-specs",
        -  "body": {
        -    "extra_pip_requirements": {
        -      "requirements": [
        -        "numpy==2.1.0"
        -      ]
        -    },
        -    "features": [
        -      {
        -        "feature_lookup": {
        -          "feature_names": [
        -            "age",
        -            "country"
        -          ],
        -          "lookup_keys": [
        -            "user_id"
        -          ],
        -          "table": "main.fspec_[UNIQUE_NAME].user_features"
        -        }
        -      },
        -      {
        -        "feature_function": {
        -          "input_bindings": [
        -            {
        -              "bound_feature": "age",
        -              "parameter": "x"
        -            }
        -          ],
        -          "output": "score",
        -          "udf": "main.fspec_[UNIQUE_NAME].score"
        -        }
        -      }
        -    ],
        -    "name": "[SPEC1_ID]"
        -  }
        -}
        -
        -=== Summary should show the id and the Catalog Explorer url
        ->>> [CLI] bundle summary -o json
        -{
        -  "id": "[SPEC1_ID]",
        -  "url": "[DATABRICKS_URL]/explore/data/functions/main/fspec_[UNIQUE_NAME]/myspec?w=[WORKSPACE_ID]"
        -}
        -
        -=== A second plan on an unchanged bundle must report no changes
        ->>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged
        -
        -=== Change a field (every field is immutable, so this recreates)
        ->>> update_file.py databricks.yml [age, country] [age]
        -
        ->>> [CLI] bundle plan
        -recreate feature_specs.spec1
        -
        -Plan: 1 to add, 0 to change, 1 to delete, 0 unchanged
        -
        ->>> [CLI] bundle deploy --auto-approve
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-basic-[UNIQUE_NAME]/default/files...
        -
        -This action will result in the deletion or recreation of the following feature specs.
        -Grants on them that are not declared in the bundle are lost:
        -  recreate resources.feature_specs.spec1
        -Recreated feature_specs.spec1
        -Files: 1 uploaded, 0 deleted
        -Resources: 1 created, 0 changed, 1 deleted, 0 unchanged
        -
        ->>> print_requests.py //feature-engineering
        -{
        -  "method": "DELETE",
        -  "path": "/api/2.0/feature-engineering/feature-specs/[SPEC1_ID]"
        -}
        -{
        -  "method": "POST",
        -  "path": "/api/2.0/feature-engineering/feature-specs",
        -  "body": {
        -    "extra_pip_requirements": {
        -      "requirements": [
        -        "numpy==2.1.0"
        -      ]
        -    },
        -    "features": [
        -      {
        -        "feature_lookup": {
        -          "feature_names": [
        -            "age"
        -          ],
        -          "lookup_keys": [
        -            "user_id"
        -          ],
        -          "table": "main.fspec_[UNIQUE_NAME].user_features"
        -        }
        -      },
        -      {
        -        "feature_function": {
        -          "input_bindings": [
        -            {
        -              "bound_feature": "age",
        -              "parameter": "x"
        -            }
        -          ],
        -          "output": "score",
        -          "udf": "main.fspec_[UNIQUE_NAME].score"
        -        }
        -      }
        -    ],
        -    "name": "[SPEC1_ID]"
        -  }
        -}
        -
        ->>> [CLI] bundle destroy --auto-approve
        -The following resources will be deleted:
        -  delete resources.feature_specs.spec1
        -
        -This action will result in the deletion of the following feature specs.
        -Feature Serving endpoints and training code that use them can no longer load them:
        -  delete resources.feature_specs.spec1
        -
        -All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-basic-[UNIQUE_NAME]/default
        -
        -Destroy: 1 deleted
        -
        ->>> print_requests.py //feature-engineering
        -{
        -  "method": "DELETE",
        -  "path": "/api/2.0/feature-engineering/feature-specs/[SPEC1_ID]"
        -}
        +Exit code: 1
... (13 more lines truncated, raise DATABRICKS_CLI_TEST_MAX_LOG to see more)

latest (v1.24.0):

acceptance_test.go:1345: Diff:
        --- bundle/resources/feature_specs/basic/output.txt
        +++ /tmp/TestAcceptbundleresourcesfeature_specsbasicDMS=3214035557/002/output.txt
        @@ -8,174 +8,30 @@
         
         === Initial summary before deploy
         >>> [CLI] bundle summary -o json
        -{
        -  "extra_pip_requirements": {
        -    "requirements": [
        -      "numpy==2.1.0"
        -    ]
        -  },
        -  "features": [
        -    {
        -      "feature_lookup": {
        -        "feature_names": [
        -          "age",
        -          "country"
        -        ],
        -        "lookup_keys": [
        -          "user_id"
        -        ],
        -        "table": "main.fspec_[UNIQUE_NAME].user_features"
        -      }
        -    },
        -    {
        -      "feature_function": {
        -        "input_bindings": [
        -          {
        -            "bound_feature": "age",
        -            "parameter": "x"
        -          }
        -        ],
        -        "output": "score",
        -        "udf": "main.fspec_[UNIQUE_NAME].score"
        -      }
        -    }
        -  ],
        -  "modified_status": "created",
        -  "name": "[SPEC1_ID]"
        -}
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        +null
        +
         >>> [CLI] bundle deploy
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
        +
         Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-basic-[UNIQUE_NAME]/default/files...
        -Created feature_specs.spec1
         Files: 2 uploaded, 0 deleted
        -Resources: 1 created, 0 changed, 0 deleted, 0 unchanged
        +Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        +Traceback (most recent call last):
        +  File "[TESTROOT]/bin/replace_ids.py", line 68, in <module>
        +    main()
        +    ~~~~^^
        +  File "[TESTROOT]/bin/replace_ids.py", line 63, in main
        +    for name, id in it:
        +                    ^^
        +  File "[TESTROOT]/bin/replace_ids.py", line 18, in iter_ids_terraform
        +    raw = open(filename).read()
        +          ~~~~^^^^^^^^^^
        +FileNotFoundError: [Errno 2] No such file or directory: '.databricks/bundle/default/terraform/terraform.tfstate'
         
        ->>> print_requests.py //feature-engineering
        -{
        -  "method": "POST",
        -  "path": "/api/2.0/feature-engineering/feature-specs",
        -  "body": {
        -    "extra_pip_requirements": {
        -      "requirements": [
        -        "numpy==2.1.0"
        -      ]
        -    },
        -    "features": [
        -      {
        -        "feature_lookup": {
        -          "feature_names": [
        -            "age",
        -            "country"
        -          ],
        -          "lookup_keys": [
        -            "user_id"
        -          ],
        -          "table": "main.fspec_[UNIQUE_NAME].user_features"
        -        }
        -      },
        -      {
        -        "feature_function": {
        -          "input_bindings": [
        -            {
        -              "bound_feature": "age",
        -              "parameter": "x"
        -            }
        -          ],
        -          "output": "score",
        -          "udf": "main.fspec_[UNIQUE_NAME].score"
        -        }
        -      }
        -    ],
        -    "name": "[SPEC1_ID]"
        -  }
        -}
        -
        -=== Summary should show the id and the Catalog Explorer url
        ->>> [CLI] bundle summary -o json
        -{
        -  "id": "[SPEC1_ID]",
        -  "url": "[DATABRICKS_URL]/explore/data/functions/main/fspec_[UNIQUE_NAME]/myspec?w=[WORKSPACE_ID]"
        -}
        -
        -=== A second plan on an unchanged bundle must report no changes
        ->>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged
        -
        -=== Change a field (every field is immutable, so this recreates)
        ->>> update_file.py databricks.yml [age, country] [age]
        -
        ->>> [CLI] bundle plan
        -recreate feature_specs.spec1
        -
        -Plan: 1 to add, 0 to change, 1 to delete, 0 unchanged
        -
        ->>> [CLI] bundle deploy --auto-approve
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-basic-[UNIQUE_NAME]/default/files...
        -
        -This action will result in the deletion or recreation of the following feature specs.
        -Grants on them that are not declared in the bundle are lost:
        -  recreate resources.feature_specs.spec1
        -Recreated feature_specs.spec1
        -Files: 1 uploaded, 0 deleted
        -Resources: 1 created, 0 changed, 1 deleted, 0 unchanged
        -
        ->>> print_requests.py //feature-engineering
        -{
        -  "method": "DELETE",
        -  "path": "/api/2.0/feature-engineering/feature-specs/[SPEC1_ID]"
        -}
        -{
        -  "method": "POST",
        -  "path": "/api/2.0/feature-engineering/feature-specs",
        -  "body": {
        -    "extra_pip_requirements": {
        -      "requirements": [
        -        "numpy==2.1.0"
        -      ]
        -    },
        -    "features": [
        -      {
        -        "feature_lookup": {
        -          "feature_names": [
        -            "age"
        -          ],
        -          "lookup_keys": [
        -            "user_id"
        -          ],
        -          "table": "main.fspec_[UNIQUE_NAME].user_features"
        -        }
        -      },
        -      {
        -        "feature_function": {
        -          "input_bindings": [
        -            {
        -              "bound_feature": "age",
        -              "parameter": "x"
        -            }
        -          ],
        -          "output": "score",
        -          "udf": "main.fspec_[UNIQUE_NAME].score"
        -        }
        -      }
        -    ],
        -    "name": "[SPEC1_ID]"
        -  }
        -}
        -
        ->>> [CLI] bundle destroy --auto-approve
        -The following resources will be deleted:
        -  delete resources.feature_specs.spec1
        -
        -This action will result in the deletion of the following feature specs.
        -Feature Serving endpoints and training code that use them can no longer load them:
        -  delete resources.feature_specs.spec1
        -
        -All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-basic-[UNIQUE_NAME]/default
        -
        -Destroy: 1 deleted
        -
        ->>> print_requests.py //feature-engineering
        -{
        -  "method": "DELETE",
        -  "path": "/api/2.0/feature-engineering/feature-specs/[SPEC1_ID]"
        -}
        +Exit code: 1
... (12 more lines truncated, raise DATABRICKS_CLI_TEST_MAX_LOG to see more)
TestAccept/bundle/resources/feature_specs/order/DMS=: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1345: Diff:
        --- bundle/resources/feature_specs/order/output.txt
        +++ /tmp/TestAcceptbundleresourcesfeature_specsorderDMS=218335654/002/output.txt
        @@ -7,29 +7,35 @@
         >>> create_feature_spec_fixtures.py main.fspec_[UNIQUE_NAME]
         
         >>> [CLI] bundle deploy
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
        +
         Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-order-[UNIQUE_NAME]/default/files...
        -Created feature_specs.spec1
         Files: 4 uploaded, 0 deleted
        -Resources: 1 created, 0 changed, 0 deleted, 0 unchanged
        +Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
         
         === Reorder the lists whose order means nothing: no changes
         >>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        +Plan: 0 to add, 0 to change, 0 to delete, 0 unchanged
        +
         === Also reorder the lookup keys, which must follow the table's primary key: recreate
         >>> [CLI] bundle plan
        -recreate feature_specs.spec1
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        -Plan: 1 to add, 0 to change, 1 to delete, 0 unchanged
        +Plan: 0 to add, 0 to change, 0 to delete, 0 unchanged
         
         >>> [CLI] bundle destroy --auto-approve
        -The following resources will be deleted:
        -  delete resources.feature_specs.spec1
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        -This action will result in the deletion of the following feature specs.
        -Feature Serving endpoints and training code that use them can no longer load them:
        -  delete resources.feature_specs.spec1
        -
         All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-order-[UNIQUE_NAME]/default
         
        -Destroy: 1 deleted
        +Destroy: 0 deleted
        
    acceptance_test.go:1123: 
        LOG.cleanup: Warning: unknown field: feature_specs
        LOG.cleanup:   at resources
        LOG.cleanup:   in databricks.yml:5:3
        LOG.cleanup: 
        LOG.cleanup: No active deployment found to destroy!
        LOG.cleanup: Warning: unknown field: feature_specs
        LOG.cleanup:   at resources
        LOG.cleanup:   in databricks.yml:5:3

latest (v1.24.0): same output as main (21db1be)

TestAccept/bundle/resources/feature_specs/remote-delete/DMS=: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1345: 
        	Error Trace:	/home/runner/work/cli/cli/libs/testdiff/testdiff.go:22
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1345
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1086
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:660
        	Error:      	Not equal: 
        	            	expected: "\n>>> [CLI] schemas create fspec_[UNIQUE_NAME] main -o json\n{\n  \"full_name\": \"main.fspec_[UNIQUE_NAME]\"\n}\n\n>>> create_feature_spec_fixtures.py main.fspec_[UNIQUE_NAME]\n\n>>> [CLI] bundle deploy\nUploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-remote-delete-[UNIQUE_NAME]/default/files...\nCreated feature_specs.spec1\nFiles: 2 uploaded, 0 deleted\nResources: 1 created, 0 changed, 0 deleted, 0 unchanged\n\n=== Delete the feature spec out of band\n>>> [CLI] api delete /api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].myspec\n{}\n\n=== Plan should detect the feature spec is gone and re-create it\n>>> [CLI] bundle plan\ncreate feature_specs.spec1\n\nPlan: 1 to add, 0 to change, 0 to delete, 0 unchanged\n\n>>> [CLI] bundle destroy --auto-approve\nAll files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-remote-delete-[UNIQUE_NAME]/default\n\nDestroy: 0 deleted\n"
        	            	actual  : "\n>>> [CLI] schemas create fspec_[UNIQUE_NAME] main -o json\n{\n  \"full_name\": \"main.fspec_[UNIQUE_NAME]\"\n}\n\n>>> create_feature_spec_fixtures.py main.fspec_[UNIQUE_NAME]\n\n>>> [CLI] bundle deploy\nWarning: unknown field: feature_specs\n  at resources\n  in databricks.yml:5:3\n\nUploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-remote-delete-[UNIQUE_NAME]/default/files...\nFiles: 2 uploaded, 0 deleted\nResources: 0 created, 0 changed, 0 deleted, 0 unchanged\n\n=== Delete the feature spec out of band\n>>> [CLI] api delete /api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].myspec\nError: Function 'main.fspec_[UNIQUE_NAME].myspec' does not exist.\n\nExit code: 1\n"
        	            	
        	            	Diff:
        	            	--- Expected
        	            	+++ Actual
        	            	@@ -9,6 +9,9 @@
        	            	 >>> [CLI] bundle deploy
        	            	+Warning: unknown field: feature_specs
        	            	+  at resources
        	            	+  in databricks.yml:5:3
        	            	+
        	            	 Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-remote-delete-[UNIQUE_NAME]/default/files...
        	            	-Created feature_specs.spec1
        	            	 Files: 2 uploaded, 0 deleted
        	            	-Resources: 1 created, 0 changed, 0 deleted, 0 unchanged
        	            	+Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        	            	 
        	            	@@ -16,14 +19,5 @@
        	            	 >>> [CLI] api delete /api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].myspec
        	            	-{}
        	            	+Error: Function 'main.fspec_[UNIQUE_NAME].myspec' does not exist.
        	            	 
        	            	-=== Plan should detect the feature spec is gone and re-create it
        	            	->>> [CLI] bundle plan
        	            	-create feature_specs.spec1
        	            	+Exit code: 1
        	            	 
        	            	-Plan: 1 to add, 0 to change, 0 to delete, 0 unchanged
        	            	-
        	            	->>> [CLI] bundle destroy --auto-approve
        	            	-All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-remote-delete-[UNIQUE_NAME]/default
        	            	-
        	            	-Destroy: 0 deleted
        	            	-
        	Test:       	TestAccept/bundle/resources/feature_specs/remote-delete/DMS=
        	Messages:   	bundle/resources/feature_specs/remote-delete/output.txt vs /tmp/TestAcceptbundleresourcesfeature_specsremote-deleteDMS=2535986827/002/output.txt
    acceptance_test.go:1123: 
        LOG.cleanup: Warning: unknown field: feature_specs
        LOG.cleanup:   at resources
        LOG.cleanup:   in databricks.yml:5:3
        LOG.cleanup: 
        LOG.cleanup: All files and directories at the following location will be deleted: /Workspace/Users/tester@databricks.com/.bundle/test-feature-specs-remote-delete-qbjnyimogvfchkujyvi5xmst7a/default
        LOG.cleanup: 
        LOG.cleanup: Destroy: 0 deleted
        LOG.cleanup: Warning: unknown field: feature_specs
        LOG.cleanup:   at resources
        LOG.cleanup:   in databricks.yml:5:3

latest (v1.24.0):

acceptance_test.go:1345: 
        	Error Trace:	/home/runner/work/cli/cli/libs/testdiff/testdiff.go:22
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1345
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:1086
        	            				/home/runner/work/cli/cli/acceptance/acceptance_test.go:660
        	Error:      	Not equal: 
        	            	expected: "\n>>> [CLI] schemas create fspec_[UNIQUE_NAME] main -o json\n{\n  \"full_name\": \"main.fspec_[UNIQUE_NAME]\"\n}\n\n>>> create_feature_spec_fixtures.py main.fspec_[UNIQUE_NAME]\n\n>>> [CLI] bundle deploy\nUploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-remote-delete-[UNIQUE_NAME]/default/files...\nCreated feature_specs.spec1\nFiles: 2 uploaded, 0 deleted\nResources: 1 created, 0 changed, 0 deleted, 0 unchanged\n\n=== Delete the feature spec out of band\n>>> [CLI] api delete /api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].myspec\n{}\n\n=== Plan should detect the feature spec is gone and re-create it\n>>> [CLI] bundle plan\ncreate feature_specs.spec1\n\nPlan: 1 to add, 0 to change, 0 to delete, 0 unchanged\n\n>>> [CLI] bundle destroy --auto-approve\nAll files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-remote-delete-[UNIQUE_NAME]/default\n\nDestroy: 0 deleted\n"
        	            	actual  : "\n>>> [CLI] schemas create fspec_[UNIQUE_NAME] main -o json\n{\n  \"full_name\": \"main.fspec_[UNIQUE_NAME]\"\n}\n\n>>> create_feature_spec_fixtures.py main.fspec_[UNIQUE_NAME]\n\n>>> [CLI] bundle deploy\nWarning: unknown field: feature_specs\n  at resources\n  in databricks.yml:5:3\n\nUploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-remote-delete-[UNIQUE_NAME]/default/files...\nFiles: 2 uploaded, 0 deleted\nResources: 0 created, 0 changed, 0 deleted, 0 unchanged\n\n=== Delete the feature spec out of band\n>>> [CLI] api delete /api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].myspec\nError: Function 'main.fspec_[UNIQUE_NAME].myspec' does not exist.\n\nExit code: 1\n"
        	            	
        	            	Diff:
        	            	--- Expected
        	            	+++ Actual
        	            	@@ -9,6 +9,9 @@
        	            	 >>> [CLI] bundle deploy
        	            	+Warning: unknown field: feature_specs
        	            	+  at resources
        	            	+  in databricks.yml:5:3
        	            	+
        	            	 Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-remote-delete-[UNIQUE_NAME]/default/files...
        	            	-Created feature_specs.spec1
        	            	 Files: 2 uploaded, 0 deleted
        	            	-Resources: 1 created, 0 changed, 0 deleted, 0 unchanged
        	            	+Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
        	            	 
        	            	@@ -16,14 +19,5 @@
        	            	 >>> [CLI] api delete /api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].myspec
        	            	-{}
        	            	+Error: Function 'main.fspec_[UNIQUE_NAME].myspec' does not exist.
        	            	 
        	            	-=== Plan should detect the feature spec is gone and re-create it
        	            	->>> [CLI] bundle plan
        	            	-create feature_specs.spec1
        	            	+Exit code: 1
        	            	 
        	            	-Plan: 1 to add, 0 to change, 0 to delete, 0 unchanged
        	            	-
        	            	->>> [CLI] bundle destroy --auto-approve
        	            	-All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-remote-delete-[UNIQUE_NAME]/default
        	            	-
        	            	-Destroy: 0 deleted
        	            	-
        	Test:       	TestAccept/bundle/resources/feature_specs/remote-delete/DMS=
        	Messages:   	bundle/resources/feature_specs/remote-delete/output.txt vs /tmp/TestAcceptbundleresourcesfeature_specsremote-deleteDMS=4052563149/002/output.txt
    acceptance_test.go:1123: 
        LOG.cleanup: Warning: unknown field: feature_specs
        LOG.cleanup:   at resources
        LOG.cleanup:   in databricks.yml:5:3
        LOG.cleanup: 
        LOG.cleanup: All files and directories at the following location will be deleted: /Workspace/Users/tester@databricks.com/.bundle/test-feature-specs-remote-delete-nsbqeyjrtjfmpak2xdxdvr75za/default
        LOG.cleanup: 
        LOG.cleanup: Destroy: 0 deleted
        LOG.cleanup: Warning: unknown field: feature_specs
        LOG.cleanup:   at resources
        LOG.cleanup:   in databricks.yml:5:3
TestAccept/bundle/resources/feature_specs/uppercase-name/DMS=: branch ✅ | main (21db1be) ❌ | latest (v1.24.0) ❌

main (21db1be):

acceptance_test.go:1345: Diff:
        --- bundle/resources/feature_specs/uppercase-name/output.txt
        +++ /tmp/TestAcceptbundleresourcesfeature_specsuppercase-nameDMS=1105352673/002/output.txt
        @@ -7,112 +7,67 @@
         >>> create_feature_spec_fixtures.py main.fspec_[UNIQUE_NAME]
         
         >>> [CLI] bundle deploy
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
        +
         Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-uppercase-name-[UNIQUE_NAME]/default/files...
        -Created feature_specs.spec1
         Files: 2 uploaded, 0 deleted
        -Resources: 1 created, 0 changed, 0 deleted, 0 unchanged
        +Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
         
         >>> print_requests.py //feature-engineering
        -{
        -  "method": "POST",
        -  "path": "/api/2.0/feature-engineering/feature-specs",
        -  "body": {
        -    "features": [
        -      {
        -        "feature_lookup": {
        -          "feature_names": [
        -            "age"
        -          ],
        -          "lookup_keys": [
        -            "user_id"
        -          ],
        -          "table": "main.fspec_[UNIQUE_NAME].user_features"
        -        }
        -      }
        -    ],
        -    "name": "main.fspec_[UNIQUE_NAME].MySpec"
        -  }
        -}
         
         === UC lowercases the name, so the id is lowercase
         >>> [CLI] bundle summary -o json
        -"main.fspec_[UNIQUE_NAME].myspec"
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        +null
        +
         === A plan on an unchanged bundle skips the name instead of recreating the feature spec
         >>> [CLI] bundle plan -o json
        -{
        -  "resources.feature_specs.spec1": {
        -    "action": "skip",
        -    "changes": {
        -      "name": {
        -        "action": "skip",
        -        "reason": "id_field"
        -      }
        -    }
        -  }
        -}
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        +{}
        +
         >>> [CLI] bundle plan
        -Plan: 0 to add, 0 to change, 0 to delete, 1 unchanged
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        +Plan: 0 to add, 0 to change, 0 to delete, 0 unchanged
        +
         === Renaming the feature spec still recreates it
         >>> update_file.py databricks.yml .MySpec .MyOtherSpec
         
         >>> [CLI] bundle plan
        -recreate feature_specs.spec1
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        -Plan: 1 to add, 0 to change, 1 to delete, 0 unchanged
        +Plan: 0 to add, 0 to change, 0 to delete, 0 unchanged
         
         >>> [CLI] bundle deploy --auto-approve
        -Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-uppercase-name-[UNIQUE_NAME]/default/files...
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        -This action will result in the deletion or recreation of the following feature specs.
        -Grants on them that are not declared in the bundle are lost:
        -  recreate resources.feature_specs.spec1
        -Recreated feature_specs.spec1
        +Uploading bundle files to /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-uppercase-name-[UNIQUE_NAME]/default/files...
         Files: 1 uploaded, 0 deleted
        -Resources: 1 created, 0 changed, 1 deleted, 0 unchanged
        +Resources: 0 created, 0 changed, 0 deleted, 0 unchanged
         
         >>> print_requests.py //feature-engineering
        -{
        -  "method": "DELETE",
        -  "path": "/api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].myspec"
        -}
        -{
        -  "method": "POST",
        -  "path": "/api/2.0/feature-engineering/feature-specs",
        -  "body": {
        -    "features": [
        -      {
        -        "feature_lookup": {
        -          "feature_names": [
        -            "age"
        -          ],
        -          "lookup_keys": [
        -            "user_id"
        -          ],
        -          "table": "main.fspec_[UNIQUE_NAME].user_features"
        -        }
        -      }
        -    ],
        -    "name": "main.fspec_[UNIQUE_NAME].MyOtherSpec"
        -  }
        -}
         
         >>> [CLI] bundle destroy --auto-approve
        -The following resources will be deleted:
        -  delete resources.feature_specs.spec1
        +Warning: unknown field: feature_specs
        +  at resources
        +  in databricks.yml:5:3
         
        -This action will result in the deletion of the following feature specs.
        -Feature Serving endpoints and training code that use them can no longer load them:
        -  delete resources.feature_specs.spec1
        -
         All files and directories at the following location will be deleted: /Workspace/Users/[USERNAME]/.bundle/test-feature-specs-uppercase-name-[UNIQUE_NAME]/default
         
        -Destroy: 1 deleted
        +Destroy: 0 deleted
         
         >>> print_requests.py //feature-engineering
        -{
        -  "method": "DELETE",
        -  "path": "/api/2.0/feature-engineering/feature-specs/main.fspec_[UNIQUE_NAME].myotherspec"
        -}
        
    acceptance_test.go:1123: 
        LOG.cleanup: Warning: unknown field: feature_specs
        LOG.cleanup:   at resources
        LOG.cleanup:   in databricks.yml:5:3
        LOG.cleanup: 
        LOG.cleanup: No active deployment found to destroy!
        LOG.cleanup: Warning: unknown field: feature_specs
        LOG.cleanup:   at resources
        LOG.cleanup:   in databricks.yml:5:3

latest (v1.24.0): same output as main (21db1be)

2 more failure details omitted, see the full report in the run.

@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

❌ Integration test report

Commit: 700f5e0

Run: 42422367179

Env ❌​FAIL ✅​pass 🙈​skip Time
❌​ aws linux-2core-8gb 25 273 18 4:22
❌​ aws-windows-latest-4core-16gb 25 275 16 4:12
❌​ azure linux-2core-8gb 25 272 18 4:18
❌​ azure-windows-latest-4core-16gb 25 274 16 3:50
❌​ gcp linux-2core-8gb 25 273 18 4:23
❌​ gcp-windows-latest-4core-16gb 25 275 16 4:18
25 interesting tests: 25 FAIL
Test Name aws linux-2core-8gb aws-windows-latest-4core-16gb azure linux-2core-8gb azure-windows-latest-4core-16gb gcp linux-2core-8gb gcp-windows-latest-4core-16gb
❌​ TestAccept ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/deployment/bind/feature_spec ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/deployment/bind/feature_spec/DMS= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/deployment/bind/feature_spec/DMS=true ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/continue_293 ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/continue_293/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/delete_idempotent ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/delete_idempotent/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/delete_idempotent/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN=1 ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/destroy_idempotent ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/destroy_idempotent/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN=1 ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/no_drift ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/invariant/no_drift/DMS=/INPUT_CONFIG=feature_spec.yml.tmpl/READPLAN=1 ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/feature_specs/basic ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/feature_specs/basic/DMS= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/feature_specs/order ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/feature_specs/order/DMS= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/feature_specs/remote-delete ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/feature_specs/remote-delete/DMS= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/feature_specs/uppercase-name ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/feature_specs/uppercase-name/DMS= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/grants/feature_specs ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F
❌​ TestAccept/bundle/resources/grants/feature_specs/DMS= ❌​F ❌​F ❌​F ❌​F ❌​F ❌​F

Daniel114510 and others added 2 commits November 4, 2026 22:59
Every feature spec case that deploys now sets Cloud = true, and the
invariant matrix no longer skips feature_spec.yml.tmpl on cloud.

Creating a feature spec resolves its lookup tables and UDFs in Unity
Catalog, so each case creates them in a per-run main.fspec_<unique>
schema with create_feature_spec_fixtures.py and drops the schema on
exit. Bundle names carry $UNIQUE_NAME so parallel runs do not share
state. The grants case grants to account users, which exists in every
workspace. The bind case binds a spec created outside the bundle and
plans no change.

The fake's delete now returns {} like the real endpoint.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
@Daniel114510 Daniel114510 changed the title Fs2524 feature specs [FS2524] Add Feature Spec as a Bundle Resource Nov 5, 2026
Daniel114510 and others added 5 commits November 5, 2026 17:45
Brings in the Go SDK v0.194.0 bump (#7371), which carries the FeatureSpec
API in .codegen/cli.json. Conflicts were adjacent additions next to the
postgres_data_apis resource (#7160); both sides are kept.

Co-authored-by: Isaac <no-reply@databricks.com>
Regenerated from the FeatureSpec API in .codegen/cli.json (Go SDK
v0.194.0): the bundle JSON schema, required-field validation, the direct
engine API types, the refschema field list and the PyDABs models.
configs/feature_specs.generated.yml regenerates unchanged.

Fills the three schema placeholders the resource adds, following the
features and registered_models entries. The grants example uses EXECUTE,
since a feature spec is a UC function.

Adds the python/feature_specs-support golden.

Co-authored-by: Isaac <no-reply@databricks.com>
main now builds with Go 1.27, whose modernize embedlit check flags the
embedded type name in a struct literal.

Co-authored-by: Isaac <no-reply@databricks.com>
&>> needs bash 4; the macOS runners use bash 3.2, which rejects the
scripts before they run.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
@Daniel114510
Daniel114510 marked this pull request as ready for review November 5, 2026 19:35
@Daniel114510
Daniel114510 requested review from a team as code owners November 5, 2026 19:35
UC lowercases a feature spec's name, and create and get now return it that
way. Listing name in provided_id_fields skips that read-back difference, as
it does for a schema's name, so a mixed-case name no longer recreates the
feature spec on every plan. The fake lowercases the name like the real
endpoint.

Co-authored-by: Isaac <no-reply@databricks.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DABs DABs related issues PyDABs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants