Skip to content

Add bundle bitmap for per-field telemetry - #6104

Draft
denik wants to merge 35 commits into
denik/config-force-send-fieldsfrom
denik/bundle-bitmap
Draft

denik wants to merge 35 commits into
denik/config-force-send-fieldsfrom
denik/bundle-bitmap

Conversation

@denik

@denik denik commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

Why

Today each tracked DABs feature needs custom code (a key constant plus a SetBoolValue call), so only hand-picked features are tracked. The bundle bitmap encodes the presence of every bundle config field as one bit, derived by reflecting over config.Root, so all current and future fields are covered for free (http://go/dabs-telemetry).

Stacked on #7412, which keeps an explicit false on optional config bools so the bitmap can record it.

Changes

  • Hidden databricks bundle bitmap group: schema, bitmap -o compressed|text|json (compressed is DEFLATE + base64, the default), decode (stdin, same -o, defaults to text) and update-schema [--validate]. The schema lives in bundle/bitmap/schema.txt, is embedded into the binary, and is append-only so bit positions stay stable; task generate appends new fields. Bool fields also record their value.
  • Bits describe the config as the user wrote it: Initialize marks the loaded config before it fills in defaults, the Python mutator marks the resources it adds, and the end of Initialize fills in the values of fields set through ${var.*} (so a bool set through a variable records its value and a complex variable records the fields inside it). bundle.target/bundle.environment are left out: target selection sets them on every bundle.
  • Boolean deploy telemetry lives in a typed bundle.Telemetry struct (metric tags): one assignment per call site instead of a key constant plus SetBoolValue. Flags measured per artifact or per resource are a BoolSet (SetBool(v)) and report each value taken once: *_lifecycle_started is true if any resource is started and false if any is stopped (it used to take a random resource's value), and artifact_*_is_set no longer repeats a value once per artifact. Otherwise bool_values keeps the same entries, now in field order. The bitmap is not sent yet.
  • databricks.bundles._bitmap in databricks-bundles: a self-contained decoder with the schema embedded.

Tests

Go and Python unit tests for presence, bool variants and the wire format. acceptance/bundle/bitmap/presence pins the set bits of a fixture and checks that the CLI (text, JSON) and Python decoders reproduce it; bitmap/full records the whole schema with each field's bit, split per resource type; python/telemetry covers a Python-defined resource; invariant/validate_bitmap (local-only) runs validate on every invariant config and checks that both decoders reproduce the bits from the encoded bitmap.

This pull request and its description were written by Isaac.

@denik
denik force-pushed the denik/bundle-bitmap branch from 221d417 to 39faace Compare July 30, 2026 10:11
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Jul 30, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Integration test report

Commit: e070c71

Run: 42649471888

Env ✅​pass 🙈​skip Time
✅​ aws linux-2core-8gb 271 25 4:46
✅​ aws-windows-latest-4core-16gb 273 23 3:28
✅​ azure linux-2core-8gb 270 25 4:35
✅​ azure-windows-latest-4core-16gb 272 23 3:35
✅​ gcp linux-2core-8gb 271 25 4:48
✅​ gcp-windows-latest-4core-16gb 273 23 3:01
Top 3 slowest tests (at least 2 minutes):
duration env testname
3:29 azure-windows-latest-4core-16gb TestAccept
3:19 aws-windows-latest-4core-16gb TestAccept
2:57 gcp-windows-latest-4core-16gb TestAccept

@denik
denik force-pushed the denik/bundle-bitmap branch 2 times, most recently from eb6b1f0 to 29c5b44 Compare August 3, 2026 10:01
@denik
denik force-pushed the denik/bundle-bitmap branch 2 times, most recently from 45b8bfe to 9ad0bbb Compare August 17, 2026 11:52
@github-actions

Copy link
Copy Markdown
Contributor

This PR has not received an update in a while. If you want to keep this PR open, please leave a comment below or push a new commit and auto-close will be canceled.

@github-actions github-actions Bot added the Stale label Oct 17, 2026
@denik
denik force-pushed the denik/bundle-bitmap branch from 9ad0bbb to 96a6df5 Compare November 3, 2026 16:34
@github-actions github-actions Bot added the DABs DABs related issues label Nov 3, 2026
@denik
denik force-pushed the denik/bundle-bitmap branch from 96a6df5 to f972c44 Compare November 3, 2026 16:42
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Commit: e070c7166 | Workflow run

Regression test report

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

79 tests: regression=78 unreleased=0 coverage=1 failing=0
test branch main (df79350) latest (v1.25.0)
TestAccept/bundle/bitmap/full ✅ ❌ ❌
TestAccept/bundle/bitmap/presence/DMS= ✅ ❌ ❌
TestAccept/bundle/bitmap/presence/DMS=true ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=alert.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=app.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=catalog.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=catalog_optional_fields.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=cluster.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=cluster_apply_policy_default_values.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=cluster_libraries.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=cluster_policy.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=dashboard.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=data_quality_monitor.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=database_catalog.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=database_instance.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=experiment.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=external_location.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=feature.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=genie_space.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=instance_pool.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_apply_policy_default_values_for_each_task.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_apply_policy_default_values_job_cluster.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_apply_policy_default_values_task_cluster.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_cross_resource_ref.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_escaped_refs.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_permission_ref.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_pydabs_1000_tasks.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_pydabs_10_tasks.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_run.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_run_job_ref.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_table_update_trigger.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_with_depends_on.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=job_with_task.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=model.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=model_service.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=model_serving_endpoint.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=model_serving_endpoint_telemetry.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=model_with_permissions.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=pipeline.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=pipeline_allow_duplicate_names.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=pipeline_apply_policy_default_values.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=pipeline_config_dots.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=postgres_branch.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=postgres_catalog.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=postgres_data_api.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=postgres_database.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=postgres_endpoint.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=postgres_project.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=postgres_role.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=postgres_synced_table.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=registered_model.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=schema.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=schema_empty_grants.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=schema_grant_ref.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=schema_tf_compat.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=schema_uppercase_name.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=secret.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=secret_scope.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=secret_scope_default_backend_type.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=sql_warehouse.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=synced_database_table.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=uc_trailing_slash.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=vector_search_endpoint.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=vector_search_index.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=volume.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=volume_external.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=volume_path_job_ref.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/invariant/validate_bitmap/INPUT_CONFIG=volume_uppercase_name.yml.tmpl ✅ ❌ ❌
TestAccept/bundle/python/telemetry/DMS=/PYDAB_VERSION=current ✅ ❌ ❌
TestAccept/bundle/refschema/DMS= ✅ ❌ ❌
TestAccept/bundle/refschema/DMS=true ✅ ❌ ❌
TestAccept/bundle/telemetry/deploy-app-lifecycle-started/DMS= ✅ ❌ ❌
TestAccept/bundle/telemetry/deploy/DMS= ✅ ❌ ❌
TestAccept/bundle/templates/default-python/classic/DMS=/READPLAN= ✅ ❌ ❌
TestAccept/bundle/templates/default-python/classic/DMS=/READPLAN=1 ✅ ❌ ❌
TestAccept/bundle/validate/explicit_false/DMS= ✅ ❌ ❌
TestAccept/bundle/validate/explicit_false/DMS=true ✅ ❌ ❌
TestAccept/selftest/selection ✅ ✅ ✅
TestAccept/bundle/bitmap/full: branch ✅ | main (df79350) ❌ | latest (v1.25.0) ❌

main (df79350):

acceptance_test.go:1316: Missing output file: output/postgres_endpoints.txt
    acceptance_test.go:1316: Missing output file: output/mcp_services.txt
    acceptance_test.go:1316: Missing output file: output/model_services.txt
    acceptance_test.go:1316: Missing output file: output/models.txt
    acceptance_test.go:1316: Missing output file: output/postgres_synced_tables.txt
    acceptance_test.go:1316: Missing output file: output/schemas.txt
    acceptance_test.go:1316: Missing output file: output/alerts.txt
    acceptance_test.go:1316: Missing output file: output/apps.txt
    acceptance_test.go:1316: Missing output file: output/cluster_policies.txt
    acceptance_test.go:1316: Missing output file: output/job_runs.txt
    acceptance_test.go:1316: Missing output file: output/postgres_projects.txt
    acceptance_test.go:1316: Missing output file: output/registered_models.txt
    acceptance_test.go:1316: Missing output file: output/catalogs.txt
    acceptance_test.go:1316: Missing output file: output/dashboards.txt
    acceptance_test.go:1316: Missing output file: output/experiments.txt
    acceptance_test.go:1345: Diff:
        --- bundle/bitmap/full/output/root.txt
        +++ /tmp/TestAcceptbundlebitmapfull403400679/001/output/root.txt
        @@ -1,369 +1,42 @@
        -variables	0
        -variables.*	1
        -variables.*.type	2
        -variables.*.default	3
        -variables.*.description	4
        -variables.*.sensitive	5
        -variables.*.sensitive=true	6
        -variables.*.sensitive=false	7
        -variables.*.value	8
        -variables.*.lookup	9
        -variables.*.lookup.alert	10
        -variables.*.lookup.cluster_policy	11
        -variables.*.lookup.cluster	12
        -variables.*.lookup.dashboard	13
        -variables.*.lookup.instance_pool	14
        -variables.*.lookup.job	15
        -variables.*.lookup.metastore	16
        -variables.*.lookup.notification_destination	17
        -variables.*.lookup.pipeline	18
        -variables.*.lookup.query	19
        -variables.*.lookup.service_principal	20
        -variables.*.lookup.warehouse	21
        -bundle	22
        -bundle.name	23
        -bundle.terraform	24
        -bundle.terraform.exec_path	25
        -bundle.force	26
        -bundle.force=true	27
        -bundle.force=false	28
        -bundle.git	29
        -bundle.git.branch	30
        -bundle.git.origin_url	31
        -bundle.git.commit	32
        -bundle.git.bundle_root_path	33
        -bundle.git.actual_branch	34
        -bundle.mode	35
        -bundle.compute_id	36
        -bundle.cluster_id	37
        -bundle.engine	38
        -bundle.deployment	39
        -bundle.deployment.fail_on_active_runs	40
        -bundle.deployment.fail_on_active_runs=true	41
        -bundle.deployment.fail_on_active_runs=false	42
        -bundle.deployment.lock	43
        -bundle.deployment.lock.enabled	44
        -bundle.deployment.lock.enabled=true	45
        -bundle.deployment.lock.enabled=false	46
        -bundle.deployment.lock.force	47
        -bundle.deployment.lock.force=true	48
        -bundle.deployment.lock.force=false	49
        -bundle.deployment.deployment_id	50
        -bundle.deployment.latest_version_id	51
        -bundle.databricks_cli_version	52
        -bundle.uuid	53
        -include	54
        -include[*]	55
        -workspace	56
        -workspace.host	57
        -workspace.profile	58
        -workspace.auth_type	59
        -workspace.metadata_service_url	60
        -workspace.client_id	61
        -workspace.google_service_account	62
        -workspace.azure_workspace_resource_id	63
        -workspace.azure_use_msi	64
        -workspace.azure_use_msi=true	65
        -workspace.azure_use_msi=false	66
        -workspace.azure_client_id	67
        -workspace.azure_tenant_id	68
        -workspace.azure_environment	69
        -workspace.azure_login_app_id	70
        -workspace.experimental_is_unified_host	71
        -workspace.experimental_is_unified_host=true	72
        -workspace.experimental_is_unified_host=false	73
        -workspace.account_id	74
        -workspace.workspace_id	75
        -workspace.current_user	76
        -workspace.current_user.short_name	77
        -workspace.current_user.domain_friendly_name	78
        -workspace.current_user.active	79
        -workspace.current_user.active=true	80
        -workspace.current_user.active=false	81
        -workspace.current_user.displayName	82
        -workspace.current_user.emails	83
        -workspace.current_user.emails[*]	84
        -workspace.current_user.emails[*].display	85
        -workspace.current_user.emails[*].primary	86
        -workspace.current_user.emails[*].primary=true	87
        -workspace.current_user.emails[*].primary=false	88
        -workspace.current_user.emails[*].$ref	89
        -workspace.current_user.emails[*].type	90
        -workspace.current_user.emails[*].value	91
        -workspace.current_user.entitlements	92
        -workspace.current_user.entitlements[*]	93
        -workspace.current_user.entitlements[*].display	94
        -workspace.current_user.entitlements[*].primary	95
        -workspace.current_user.entitlements[*].primary=true	96
        -workspace.current_user.entitlements[*].primary=false	97
        -workspace.current_user.entitlements[*].$ref	98
        -workspace.current_user.entitlements[*].type	99
        -workspace.current_user.entitlements[*].value	100
        -workspace.current_user.externalId	101
        -workspace.current_user.groups	102
        -workspace.current_user.groups[*]	103
        -workspace.current_user.groups[*].display	104
        -workspace.current_user.groups[*].primary	105
        -workspace.current_user.groups[*].primary=true	106
        -workspace.current_user.groups[*].primary=false	107
        -workspace.current_user.groups[*].$ref	108
        -workspace.current_user.groups[*].type	109
        -workspace.current_user.groups[*].value	110
        -workspace.current_user.id	111
        -workspace.current_user.name	112
        -workspace.current_user.name.familyName	113
        -workspace.current_user.name.givenName	114
        -workspace.current_user.roles	115
        -workspace.current_user.roles[*]	116
        -workspace.current_user.roles[*].display	117
        -workspace.current_user.roles[*].primary	118
        -workspace.current_user.roles[*].primary=true	119
        -workspace.current_user.roles[*].primary=false	120
        -workspace.current_user.roles[*].$ref	121
        -workspace.current_user.roles[*].type	122
        -workspace.current_user.roles[*].value	123
        -workspace.current_user.schemas	124
        -workspace.current_user.schemas[*]	125
        -workspace.current_user.userName	126
        -workspace.root_path	127
        -workspace.file_path	128
        -workspace.resource_path	129
        -workspace.artifact_path	130
        -workspace.state_path	131
        -workspace.sync_mode	132
        -artifacts	133
        -artifacts.*	134
        -artifacts.*.type	135
        -artifacts.*.path	136
        -artifacts.*.files	137
        -artifacts.*.files[*]	138
        -artifacts.*.files[*].source	139
        -artifacts.*.files[*].patched	140
        -artifacts.*.files[*].remote_path	141
        -artifacts.*.build	142
        -artifacts.*.executable	143
        -artifacts.*.dynamic_version	144
        -artifacts.*.dynamic_version=true	145
        -artifacts.*.dynamic_version=false	146
        -artifacts.*.include	147
        -artifacts.*.include[*]	148
        -artifacts.*.git	149
        -artifacts.*.git.branch	150
        -artifacts.*.git.commit	151
        -resources	152
        -sync	4966
        -sync.paths	4967
        -sync.paths[*]	4968
        -sync.include	4969
        -sync.include[*]	4970
        -sync.exclude	4971
        -sync.exclude[*]	4972
        -run_as	4973
        -run_as.group_name	4974
        -run_as.service_principal_name	4975
        -run_as.user_name	4976
        -presets	4977
        -presets.name_prefix	4978
        -presets.pipelines_development	4979
        -presets.pipelines_development=true	4980
        -presets.pipelines_development=false	4981
        -presets.trigger_pause_status	4982
        -presets.jobs_max_concurrent_runs	4983
        -presets.source_linked_deployment	4984
        -presets.source_linked_deployment=true	4985
        -presets.source_linked_deployment=false	4986
        -presets.artifacts_dynamic_version	4987
        -presets.artifacts_dynamic_version=true	4988
        -presets.artifacts_dynamic_version=false	4989
        -presets.tags	4990
        -presets.tags.*	4991
        -experimental	4992
        -experimental.scripts	4993
... (259 more lines truncated, raise DATABRICKS_CLI_TEST_MAX_LOG to see more)

latest (v1.25.0):

acceptance_test.go:1316: Missing output file: output/postgres_synced_tables.txt
    acceptance_test.go:1316: Missing output file: output/secret_scopes.txt
    acceptance_test.go:1316: Missing output file: output/volumes.txt
    acceptance_test.go:1316: Missing output file: output/cluster_policies.txt
    acceptance_test.go:1316: Missing output file: output/instance_pools.txt
    acceptance_test.go:1316: Missing output file: output/mcp_services.txt
    acceptance_test.go:1316: Missing output file: output/postgres_databases.txt
    acceptance_test.go:1316: Missing output file: output/schemas.txt
    acceptance_test.go:1316: Missing output file: output/secrets.txt
    acceptance_test.go:1316: Missing output file: output/experiments.txt
    acceptance_test.go:1316: Missing output file: output/data_quality_monitors.txt
    acceptance_test.go:1316: Missing output file: output/job_runs.txt
    acceptance_test.go:1316: Missing output file: output/model_serving_endpoints.txt
    acceptance_test.go:1316: Missing output file: output/postgres_data_apis.txt
    acceptance_test.go:1316: Missing output file: output/postgres_endpoints.txt
    acceptance_test.go:1345: Diff:
        --- bundle/bitmap/full/output/root.txt
        +++ /tmp/TestAcceptbundlebitmapfull3573192831/001/output/root.txt
        @@ -1,369 +1,42 @@
        -variables	0
        -variables.*	1
        -variables.*.type	2
        -variables.*.default	3
        -variables.*.description	4
        -variables.*.sensitive	5
        -variables.*.sensitive=true	6
        -variables.*.sensitive=false	7
        -variables.*.value	8
        -variables.*.lookup	9
        -variables.*.lookup.alert	10
        -variables.*.lookup.cluster_policy	11
        -variables.*.lookup.cluster	12
        -variables.*.lookup.dashboard	13
        -variables.*.lookup.instance_pool	14
        -variables.*.lookup.job	15
        -variables.*.lookup.metastore	16
        -variables.*.lookup.notification_destination	17
        -variables.*.lookup.pipeline	18
        -variables.*.lookup.query	19
        -variables.*.lookup.service_principal	20
        -variables.*.lookup.warehouse	21
        -bundle	22
        -bundle.name	23
        -bundle.terraform	24
        -bundle.terraform.exec_path	25
        -bundle.force	26
        -bundle.force=true	27
        -bundle.force=false	28
        -bundle.git	29
        -bundle.git.branch	30
        -bundle.git.origin_url	31
        -bundle.git.commit	32
        -bundle.git.bundle_root_path	33
        -bundle.git.actual_branch	34
        -bundle.mode	35
        -bundle.compute_id	36
        -bundle.cluster_id	37
        -bundle.engine	38
        -bundle.deployment	39
        -bundle.deployment.fail_on_active_runs	40
        -bundle.deployment.fail_on_active_runs=true	41
        -bundle.deployment.fail_on_active_runs=false	42
        -bundle.deployment.lock	43
        -bundle.deployment.lock.enabled	44
        -bundle.deployment.lock.enabled=true	45
        -bundle.deployment.lock.enabled=false	46
        -bundle.deployment.lock.force	47
        -bundle.deployment.lock.force=true	48
        -bundle.deployment.lock.force=false	49
        -bundle.deployment.deployment_id	50
        -bundle.deployment.latest_version_id	51
        -bundle.databricks_cli_version	52
        -bundle.uuid	53
        -include	54
        -include[*]	55
        -workspace	56
        -workspace.host	57
        -workspace.profile	58
        -workspace.auth_type	59
        -workspace.metadata_service_url	60
        -workspace.client_id	61
        -workspace.google_service_account	62
        -workspace.azure_workspace_resource_id	63
        -workspace.azure_use_msi	64
        -workspace.azure_use_msi=true	65
        -workspace.azure_use_msi=false	66
        -workspace.azure_client_id	67
        -workspace.azure_tenant_id	68
        -workspace.azure_environment	69
        -workspace.azure_login_app_id	70
        -workspace.experimental_is_unified_host	71
        -workspace.experimental_is_unified_host=true	72
        -workspace.experimental_is_unified_host=false	73
        -workspace.account_id	74
        -workspace.workspace_id	75
        -workspace.current_user	76
        -workspace.current_user.short_name	77
        -workspace.current_user.domain_friendly_name	78
        -workspace.current_user.active	79
        -workspace.current_user.active=true	80
        -workspace.current_user.active=false	81
        -workspace.current_user.displayName	82
        -workspace.current_user.emails	83
        -workspace.current_user.emails[*]	84
        -workspace.current_user.emails[*].display	85
        -workspace.current_user.emails[*].primary	86
        -workspace.current_user.emails[*].primary=true	87
        -workspace.current_user.emails[*].primary=false	88
        -workspace.current_user.emails[*].$ref	89
        -workspace.current_user.emails[*].type	90
        -workspace.current_user.emails[*].value	91
        -workspace.current_user.entitlements	92
        -workspace.current_user.entitlements[*]	93
        -workspace.current_user.entitlements[*].display	94
        -workspace.current_user.entitlements[*].primary	95
        -workspace.current_user.entitlements[*].primary=true	96
        -workspace.current_user.entitlements[*].primary=false	97
        -workspace.current_user.entitlements[*].$ref	98
        -workspace.current_user.entitlements[*].type	99
        -workspace.current_user.entitlements[*].value	100
        -workspace.current_user.externalId	101
        -workspace.current_user.groups	102
        -workspace.current_user.groups[*]	103
        -workspace.current_user.groups[*].display	104
        -workspace.current_user.groups[*].primary	105
        -workspace.current_user.groups[*].primary=true	106
        -workspace.current_user.groups[*].primary=false	107
        -workspace.current_user.groups[*].$ref	108
        -workspace.current_user.groups[*].type	109
        -workspace.current_user.groups[*].value	110
        -workspace.current_user.id	111
        -workspace.current_user.name	112
        -workspace.current_user.name.familyName	113
        -workspace.current_user.name.givenName	114
        -workspace.current_user.roles	115
        -workspace.current_user.roles[*]	116
        -workspace.current_user.roles[*].display	117
        -workspace.current_user.roles[*].primary	118
        -workspace.current_user.roles[*].primary=true	119
        -workspace.current_user.roles[*].primary=false	120
        -workspace.current_user.roles[*].$ref	121
        -workspace.current_user.roles[*].type	122
        -workspace.current_user.roles[*].value	123
        -workspace.current_user.schemas	124
        -workspace.current_user.schemas[*]	125
        -workspace.current_user.userName	126
        -workspace.root_path	127
        -workspace.file_path	128
        -workspace.resource_path	129
        -workspace.artifact_path	130
        -workspace.state_path	131
        -workspace.sync_mode	132
        -artifacts	133
        -artifacts.*	134
        -artifacts.*.type	135
        -artifacts.*.path	136
        -artifacts.*.files	137
        -artifacts.*.files[*]	138
        -artifacts.*.files[*].source	139
        -artifacts.*.files[*].patched	140
        -artifacts.*.files[*].remote_path	141
        -artifacts.*.build	142
        -artifacts.*.executable	143
        -artifacts.*.dynamic_version	144
        -artifacts.*.dynamic_version=true	145
        -artifacts.*.dynamic_version=false	146
        -artifacts.*.include	147
        -artifacts.*.include[*]	148
        -artifacts.*.git	149
        -artifacts.*.git.branch	150
        -artifacts.*.git.commit	151
        -resources	152
        -sync	4966
        -sync.paths	4967
        -sync.paths[*]	4968
        -sync.include	4969
        -sync.include[*]	4970
        -sync.exclude	4971
        -sync.exclude[*]	4972
        -run_as	4973
        -run_as.group_name	4974
        -run_as.service_principal_name	4975
        -run_as.user_name	4976
        -presets	4977
        -presets.name_prefix	4978
        -presets.pipelines_development	4979
        -presets.pipelines_development=true	4980
        -presets.pipelines_development=false	4981
        -presets.trigger_pause_status	4982
        -presets.jobs_max_concurrent_runs	4983
        -presets.source_linked_deployment	4984
        -presets.source_linked_deployment=true	4985
        -presets.source_linked_deployment=false	4986
        -presets.artifacts_dynamic_version	4987
        -presets.artifacts_dynamic_version=true	4988
        -presets.artifacts_dynamic_version=false	4989
        -presets.tags	4990
        -presets.tags.*	4991
        -experimental	4992
        -experimental.scripts	4993
... (259 more lines truncated, raise DATABRICKS_CLI_TEST_MAX_LOG to see more)
TestAccept/bundle/bitmap/presence/DMS=: branch ✅ | main (df79350) ❌ | latest (v1.25.0) ❌

main (df79350):

acceptance_test.go:1345: Diff:
        --- bundle/bitmap/presence/output.txt
        +++ /tmp/TestAcceptbundlebitmappresenceDMS=4142733522/002/output.txt
        @@ -10,46 +10,36 @@
         >>> [CLI] bundle bitmap decode -o json
         
         >>> [CLI] bundle bitmap decode -o compressed
        +Error: invalid argument "compressed" for "-o, --output" flag: accepted arguments are json and text
         
        ->>> uv run --isolated --no-project --reinstall-package databricks-bundles --with [DATABRICKS_BUNDLES_WHEEL] -q python -m databricks.bundles._bitmap
        -
        ->>> [CLI] bundle bitmap update-schema --validate
        -
        -=== decode rejects input that is not an encoded bitmap
        -
        ->>> musterr [CLI] bundle bitmap decode
        -Error: base64: illegal base64 data at input byte 3
        -
        -=== -o accepts compressed, text and json
        -
        ->>> musterr [CLI] bundle bitmap bitmap -o yaml
        -Error: invalid argument "yaml" for "-o, --output" flag: accepted values are compressed, text and json
        -
         Usage:
        -  databricks bundle bitmap bitmap [flags]
        +  databricks bundle [command]
         
        +Available Commands:
        +  deploy             Deploy bundle
        +  deployment         Deployment related commands
        +  destroy            Destroy deployed bundle resources
        +  generate           Generate bundle configuration
        +  init               Initialize using a bundle template
        +  open               Open a resource in the browser
        +  plan               Show deployment plan
        +  run                Run a job, pipeline update or app
        +  schema             Generate JSON Schema for bundle configuration
        +  summary            Summarize resources deployed by this bundle
        +  sync               Synchronize bundle tree to the workspace
        +  validate           Validate configuration
        +
         Flags:
        -  -h, --help            help for bitmap
        -  -o, --output format   output format:
        -                          compressed: base64 of the DEFLATE-compressed wire format
        -                          text:       a "size=N context=C" header, then one "<value> <field>" line per
        -                                      set field: "T" or "F" for a boolean field holding that value, "1"
        -                                      for any other field; unset fields are omitted
        -                          json:       size, context, and trees of the fields present ("presence") and of
        -                                      the boolean fields seen holding "true" and "false" (default compressed)
        +  -h, --help          help for bundle
        +      --var strings   set values for variables defined in bundle config. Example: --var="foo=bar"
         
         Global Flags:
               --debug            enable debug logging
        +  -o, --output type      output type: text or json (default text)
           -p, --profile string   ~/.databrickscfg profile
           -t, --target string    bundle target to use (if applicable)
        -      --var strings      set values for variables defined in bundle config. Example: --var="foo=bar"
         
        +Use "databricks bundle [command] --help" for more information about a command.
         
        -=== An invalid bundle fails instead of printing a bitmap
         
        ->>> musterr [CLI] bundle bitmap bitmap
        -Error: Artifact not properly configured
        -  in databricks.yml:5:10
        -
        -please specify artifact properties
        -
        +Exit code: 1
        
    acceptance_test.go:1345: Diff:
        --- bundle/bitmap/presence/out.bitmap.json
        +++ /tmp/TestAcceptbundlebitmappresenceDMS=4142733522/001/out.bitmap.json
        @@ -1,164 +1,42 @@
        -{
        -  "size": [SCHEMA_SIZE],
        -  "context": 0,
        -  "presence": {
        -    "artifacts": {
        -      "*": {
        -        "build": true,
        -        "files": {
        -          "[*]": {
        -            "source": true
        -          }
        -        },
        -        "type": true
        -      }
        -    },
        -    "bundle": {
        -      "name": true
        -    },
        -    "experimental": {
        -      "use_legacy_run_as": true
        -    },
        -    "presets": {
        -      "name_prefix": true,
        -      "pipelines_development": true
        -    },
        -    "resources": {
        -      "clusters": {
        -        "*": {
        -          "cluster_name": true,
        -          "lifecycle": {
        -            "started": true
        -          }
        -        }
        -      },
        -      "jobs": {
        -        "*": {
        -          "description": true,
        -          "email_notifications": {
        -            "no_alert_for_skipped_runs": true
        -          },
        -          "job_clusters": {
        -            "[*]": {
        -              "job_cluster_key": true,
        -              "new_cluster": {
        -                "num_workers": true,
        -                "spark_version": true
        -              }
        -            }
        -          },
        -          "max_concurrent_runs": true,
        -          "name": true,
        -          "notification_settings": {
        -            "no_alert_for_skipped_runs": true
        -          },
        -          "parameters": true,
        -          "queue": {
        -            "enabled": true
        -          },
        -          "tags": {
        -            "*": true
        -          },
        -          "tasks": {
        -            "[*]": {
        -              "depends_on": {
        -                "[*]": {
        -                  "task_key": true
        -                }
        -              },
        -              "disable_auto_optimization": true,
        -              "notebook_task": {
        -                "notebook_path": true
        -              },
        -              "task_key": true
        -            }
        -          },
        -          "timeout_seconds": true
        -        }
        -      }
        -    },
        -    "run_as": {
        -      "service_principal_name": true
        -    },
        -    "telemetry": {
        -      "ArtifactBuildCommandIsSet": true,
        -      "ArtifactFilesIsSet": true,
        -      "ConfigHasDoubleDollarBrace": true,
        -      "PresetsNamePrefixIsSet": true,
        -      "RunAsSet": true,
        -      "UseLegacyRunAs": true
        -    },
        -    "variables": {
        -      "*": {
        -        "default": true,
        -        "description": true,
        -        "type": true
        -      }
        -    }
        -  },
        -  "true": {
        -    "resources": {
        -      "clusters": {
        -        "*": {
        -          "lifecycle": {
        -            "started": true
        -          }
        -        }
        -      },
        -      "jobs": {
        -        "*": {
        -          "notification_settings": {
        -            "no_alert_for_skipped_runs": true
        -          },
        -          "queue": {
        -            "enabled": true
        -          }
        -        }
        -      }
        -    },
        -    "telemetry": {
        -      "ArtifactBuildCommandIsSet": true,
        -      "ArtifactFilesIsSet": true,
        -      "ConfigHasDoubleDollarBrace": true,
        -      "PresetsNamePrefixIsSet": true,
        -      "RunAsSet": true
... (197 more lines truncated, raise DATABRICKS_CLI_TEST_MAX_LOG to see more)

latest (v1.25.0): same output as main (df79350)

TestAccept/bundle/bitmap/presence/DMS=true: branch ✅ | main (df79350) ❌ | latest (v1.25.0) ❌

main (df79350):

acceptance_test.go:1345: Diff:
        --- bundle/bitmap/presence/output.txt
        +++ /tmp/TestAcceptbundlebitmappresenceDMS=true2915518081/002/output.txt
        @@ -10,46 +10,36 @@
         >>> [CLI] bundle bitmap decode -o json
         
         >>> [CLI] bundle bitmap decode -o compressed
        +Error: invalid argument "compressed" for "-o, --output" flag: accepted arguments are json and text
         
        ->>> uv run --isolated --no-project --reinstall-package databricks-bundles --with [DATABRICKS_BUNDLES_WHEEL] -q python -m databricks.bundles._bitmap
        -
        ->>> [CLI] bundle bitmap update-schema --validate
        -
        -=== decode rejects input that is not an encoded bitmap
        -
        ->>> musterr [CLI] bundle bitmap decode
        -Error: base64: illegal base64 data at input byte 3
        -
        -=== -o accepts compressed, text and json
        -
        ->>> musterr [CLI] bundle bitmap bitmap -o yaml
        -Error: invalid argument "yaml" for "-o, --output" flag: accepted values are compressed, text and json
        -
         Usage:
        -  databricks bundle bitmap bitmap [flags]
        +  databricks bundle [command]
         
        +Available Commands:
        +  deploy             Deploy bundle
        +  deployment         Deployment related commands
        +  destroy            Destroy deployed bundle resources
        +  generate           Generate bundle configuration
        +  init               Initialize using a bundle template
        +  open               Open a resource in the browser
        +  plan               Show deployment plan
        +  run                Run a job, pipeline update or app
        +  schema             Generate JSON Schema for bundle configuration
        +  summary            Summarize resources deployed by this bundle
        +  sync               Synchronize bundle tree to the workspace
        +  validate           Validate configuration
        +
         Flags:
        -  -h, --help            help for bitmap
        -  -o, --output format   output format:
        -                          compressed: base64 of the DEFLATE-compressed wire format
        -                          text:       a "size=N context=C" header, then one "<value> <field>" line per
        -                                      set field: "T" or "F" for a boolean field holding that value, "1"
        -                                      for any other field; unset fields are omitted
        -                          json:       size, context, and trees of the fields present ("presence") and of
        -                                      the boolean fields seen holding "true" and "false" (default compressed)
        +  -h, --help          help for bundle
        +      --var strings   set values for variables defined in bundle config. Example: --var="foo=bar"
         
         Global Flags:
               --debug            enable debug logging
        +  -o, --output type      output type: text or json (default text)
           -p, --profile string   ~/.databrickscfg profile
           -t, --target string    bundle target to use (if applicable)
        -      --var strings      set values for variables defined in bundle config. Example: --var="foo=bar"
         
        +Use "databricks bundle [command] --help" for more information about a command.
         
        -=== An invalid bundle fails instead of printing a bitmap
         
        ->>> musterr [CLI] bundle bitmap bitmap
        -Error: Artifact not properly configured
        -  in databricks.yml:5:10
        -
        -please specify artifact properties
        -
        +Exit code: 1
        
    acceptance_test.go:1345: Diff:
        --- bundle/bitmap/presence/out.bitmap.json
        +++ /tmp/TestAcceptbundlebitmappresenceDMS=true2915518081/001/out.bitmap.json
        @@ -1,164 +1,42 @@
        -{
        -  "size": [SCHEMA_SIZE],
        -  "context": 0,
        -  "presence": {
        -    "artifacts": {
        -      "*": {
        -        "build": true,
        -        "files": {
        -          "[*]": {
        -            "source": true
        -          }
        -        },
        -        "type": true
        -      }
        -    },
        -    "bundle": {
        -      "name": true
        -    },
        -    "experimental": {
        -      "use_legacy_run_as": true
        -    },
        -    "presets": {
        -      "name_prefix": true,
        -      "pipelines_development": true
        -    },
        -    "resources": {
        -      "clusters": {
        -        "*": {
        -          "cluster_name": true,
        -          "lifecycle": {
        -            "started": true
        -          }
        -        }
        -      },
        -      "jobs": {
        -        "*": {
        -          "description": true,
        -          "email_notifications": {
        -            "no_alert_for_skipped_runs": true
        -          },
        -          "job_clusters": {
        -            "[*]": {
        -              "job_cluster_key": true,
        -              "new_cluster": {
        -                "num_workers": true,
        -                "spark_version": true
        -              }
        -            }
        -          },
        -          "max_concurrent_runs": true,
        -          "name": true,
        -          "notification_settings": {
        -            "no_alert_for_skipped_runs": true
        -          },
        -          "parameters": true,
        -          "queue": {
        -            "enabled": true
        -          },
        -          "tags": {
        -            "*": true
        -          },
        -          "tasks": {
        -            "[*]": {
        -              "depends_on": {
        -                "[*]": {
        -                  "task_key": true
        -                }
        -              },
        -              "disable_auto_optimization": true,
        -              "notebook_task": {
        -                "notebook_path": true
        -              },
        -              "task_key": true
        -            }
        -          },
        -          "timeout_seconds": true
        -        }
        -      }
        -    },
        -    "run_as": {
        -      "service_principal_name": true
        -    },
        -    "telemetry": {
        -      "ArtifactBuildCommandIsSet": true,
        -      "ArtifactFilesIsSet": true,
        -      "ConfigHasDoubleDollarBrace": true,
        -      "PresetsNamePrefixIsSet": true,
        -      "RunAsSet": true,
        -      "UseLegacyRunAs": true
        -    },
        -    "variables": {
        -      "*": {
        -        "default": true,
        -        "description": true,
        -        "type": true
        -      }
        -    }
        -  },
        -  "true": {
        -    "resources": {
        -      "clusters": {
        -        "*": {
        -          "lifecycle": {
        -            "started": true
        -          }
        -        }
        -      },
        -      "jobs": {
        -        "*": {
        -          "notification_settings": {
        -            "no_alert_for_skipped_runs": true
        -          },
        -          "queue": {
        -            "enabled": true
        -          }
        -        }
        -      }
        -    },
        -    "telemetry": {
        -      "ArtifactBuildCommandIsSet": true,
        -      "ArtifactFilesIsSet": true,
        -      "ConfigHasDoubleDollarBrace": true,
        -      "PresetsNamePrefixIsSet": true,
        -      "RunAsSet": true
... (197 more lines truncated, raise DATABRICKS_CLI_TEST_MAX_LOG to see more)

latest (v1.25.0): same output as main (df79350)

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

@denik
denik force-pushed the denik/bundle-bitmap branch from f972c44 to 1cc9186 Compare November 4, 2026 10:08
@github-actions github-actions Bot added the PyDABs label Nov 4, 2026
@denik
denik force-pushed the denik/bundle-bitmap branch 3 times, most recently from 5e60941 to 445b523 Compare November 5, 2026 13:52
@github-actions github-actions Bot removed the Stale label Nov 5, 2026
@denik
denik force-pushed the denik/bundle-bitmap branch from 108e307 to 6d41413 Compare November 9, 2026 15:40
@denik
denik changed the base branch from main to denik/config-force-send-fields November 9, 2026 15:40
@denik
denik added this pull request to stack #7413 November 9, 2026 15:40
denik added 8 commits November 9, 2026 16:53
Co-authored-by: Isaac
Encode presence of every bundle config field as one bit. The schema is
derived by reflecting over config.Root, recorded in bundle/bitmap/schema.txt,
and embedded into the binary. Append-only so bit positions stay stable.

Adds hidden `databricks bundle bitmap` group: schema, update-schema
[--validate], bitmap-text, bitmap. Wires generate-bitmap-schema into the
Taskfile and runs the encoder over all no_drift invariant configs.

Co-authored-by: Isaac
Kept in PR history for context; not landed.

Co-authored-by: Isaac
- Every bool/*bool field now gets a "#true" value bit in addition to its
  presence bit, so a *bool encodes unset/false/true as 00/10/11.
- decode_bitmap.py decodes the base64 bitmap against the schema; the dedicated
  acceptance test asserts it round-trips to bitmap-text.
- Record the encoded bitmap and set-bit list for the default-python template.

Co-authored-by: Isaac
Replace the string-keyed BoolValues map with a typed bundle.Telemetry struct
whose fields feed both the deploy telemetry wire (via BoolValues()) and the
bundle bitmap (namespaced under telemetry.*).

Value-bearing flags whose false is meaningful are stored as True/False pairs so
the bitmap can represent both outcomes; BoolValues() collapses each pair back to
its single wire key. libs/cache gets a concrete Metrics struct (embedded into
Telemetry) instead of the old interface.

The wire is unchanged except that redundant false entries of one-hot groups
(state_path_*, dms_undeclared_*) are no longer emitted; their true member is
preserved.

Co-authored-by: Isaac
decode_bitmap.py was committed without the executable bit, so the round-trip
step failed with "permission denied" (exit code differed across OSes, breaking
the golden). Mark it executable.

bitmap-text and bitmap are separate invocations sharing a cache dir, so the
second recorded a cache hit instead of a miss and the round-trip check
diverged. Give each its own cache dir so both observe a cold miss.

Co-authored-by: Isaac
On a CRLF checkout (Windows) the embedded schema.txt lines kept a trailing \r,
so they never matched the clean paths from WalkType. Merge's dedup then failed
and the schema doubled, breaking bundle bitmap schema/bitmap-text on Windows.
splitLines now normalizes CRLF.

Co-authored-by: Isaac
denik and others added 27 commits November 9, 2026 16:53
The schema had telemetry fields appended at the tail (from append-only merges
across a rebase). Since the PR has not landed, bit positions need not be
stable yet, so regenerate from scratch to put telemetry fields in natural walk
order.

generate-bitmap-schema now also regenerates the bitmap acceptance goldens
(out.schema.txt, out.bitmap-text.txt, encoded bitmap), which embed the schema
and depend on bit positions; otherwise they go stale when the schema changes.

Co-authored-by: Isaac
Existing telemetry (bundle/metrics AddBoolValue/SetBoolValue and the wire) is
unchanged. Add a Telemetry struct on Bundle with a field per bool flag; each
metrics call site additionally sets the matching field so the same signal
reaches the bitmap. Value-bearing flags use True/False pairs so the
presence-only bitmap can distinguish measured-false from not-measured. Fields
have no json tags, so they are invisible to the config schema and walked into
the bitmap under their Go field names (telemetry.*).

Verified the telemetry and resource_deps goldens are byte-identical to main:
the change is strictly additive to the existing wire.

Co-authored-by: Isaac
The four dms_undeclared_* flags are independent booleans recorded with
their real value on every deploy, so a measured false is meaningful (it
is the common "no undeclared writers" case). As single presence bits a
false collapsed to 0, indistinguishable from "not measured", losing the
signal. Store each as a True/False pair like the other value-bearing
flags. The telemetry wire (BoolValues) is unchanged.

Co-authored-by: Isaac
The dms_undeclared_* flags are always co-emitted with the one-hot
DMSCompat verdict, so a 0 bit is unambiguously "measured false" rather
than "not measured" — a True/False pair adds no information. A pair is
only warranted for a lone boolean with no co-located signal that the
measurement ran (e.g. run_as_set). Adds a comment recording why.

Co-authored-by: Isaac
The telemetry struct's fields have no json tags, so structwalk.Walk does
not honor omitempty and visits every field regardless of value. Bits()
ignored the visited value and set the bit on mere presence, so every
telemetry bit was 1 on every deploy (the acceptance golden showed all
mutually-exclusive one-hot members set at once). Gate the telemetry walk
on the visited bool value so a field maps to a bit only when true.

Also drop blank lines in splitLines so a stray one can never shift bit
indices in the append-only schema, and make the test stand-in tagless to
match the real struct (the tagged stand-in masked the bug).

Co-authored-by: Isaac
Rebase onto main picked up new config fields (resources.secrets.*) and
removed the acceptance Local option, which now fails as an undecoded key.

Co-authored-by: Isaac
Main added resources.pipelines.*.cascade_on_destroy, which shifts the
schema and the encoded bitmaps.

Co-authored-by: Isaac
Main moved the select/source-linked metrics into mark_select_used.go and
apply_sync_mode.go, dropped the dry-run migration metrics, and added
plan-error, recreate-planned, via-default, deployment-history,
immutable-snapshot, and ai_runtime_task metrics. Mirror them into
Telemetry, regenerate the (still unreleased) schema from scratch, and drop
the engine matrix from the bitmap test now that direct is the only engine.

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

- Compute bits from bundle.UserConfig, a snapshot of the config taken at the
  start of Initialize (plus resources added by Python before their defaults are
  filled in), so the bitmap records what users configure rather than CLI
  defaults (workspace paths, current_user, job format/queue, ...).
- Walk the dyn.Value instead of the typed struct: interface-typed fields
  (variables.*.default) and empty containers were never marked, and zero
  non-omitempty fields always were.
- Replace True/False field pairs and SetPaired with a BoolPair type; per-artifact
  flags call Set per artifact, so mixed artifacts set both bits.
- bundle bitmap now fails on an invalid bundle instead of printing a bitmap.
- Goldens record only set bits; the schema and encoded blob are scratch files
  checked by the round trip, so an added config field touches only schema.txt.
  test-acc/test-update no longer regenerate the schema and goldens first.
- Decode: overflow-safe size check; tests for header errors, byte boundaries,
  non-zero context; Python decoder checks the context; unique-schema test.
- Acceptance coverage for interface defaults, empty containers, explicit zero,
  dotted map keys, target overrides, run_as, escapes, mixed artifacts, an
  invalid bundle, and a Python-defined resource.

Co-authored-by: Isaac <no-reply@databricks.com>
Split acceptance/bundle/bitmap into presence/ (set bits, round trip, invalid
bundle) and full/, which records the complete bitmap-text so a PR adding a
config field shows where it landed. generate-bitmap-schema refreshes full/.

Co-authored-by: Isaac <no-reply@databricks.com>
- bundle.Telemetry is now the single source of the deploy event's bool_values:
  fields are bool (reported when true), *bool (a measured value) or []bool (one
  value per item), keyed by a `metric` tag. Call sites set one field instead of
  a Metrics call plus a mirror. The wire has the same entries in field order;
  has_<task_type> and local.cache.* stay in Metrics.BoolValues.
- The bitmap records each bool field's value: the schema has "=true"/"=false"
  entries after every bool field (config and telemetry).
- bitmap-text and the new `bundle bitmap decode` (stdin) print one line per set
  field: "T"/"F" for a bool value, "1" otherwise.
- acceptance/bundle/bitmap/full records the whole schema; presence covers bool
  variants (SDK omitempty false, non-omitempty true/false, *bool false, an
  unresolved reference) and pins the known gap: an explicit false on an
  omitempty bool of a CLI-defined struct is dropped by the loader.

Co-authored-by: Isaac <no-reply@databricks.com>
databricks.bundles._bitmap decodes an encoded bundle bitmap without the CLI:
it embeds the schema, raw-DEFLATE compressed and base64 encoded, and
decompresses it on import. `python -m databricks.bundles._bitmap` reads a
bitmap on stdin and prints the same lines as `bundle bitmap decode`.

bundle/bitmap/genpython writes the embedded schema; compressing in Go keeps
the generated file identical regardless of the Python's zlib build. It runs as
part of `task generate-bitmap-schema`.

The presence test and every no_drift invariant config check that the Python
decoder's output matches the CLI's. The tests pass --reinstall-package because
the wheel's version does not change with the code and uv would otherwise reuse
a cached install.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
pydabs-codegen deletes every databricks/bundles package except core before
regenerating, which removed _bitmap (and then ruff re-sorted the test's
imports). Exclude it there, and skip private packages in the generated docs.

Co-authored-by: Isaac <no-reply@databricks.com>
Configs with warnings (e.g. the deprecated pipeline development property)
leaked them into output.txt once stdout and stderr were split. Log stderr and
keep the panic check on it.

Co-authored-by: Isaac <no-reply@databricks.com>
Runs over every invariant config without deploying: bundle validate (text
and JSON) must succeed, and both the CLI and Python decoders must reproduce
the bitmap-text bits from the encoded bitmap. Replaces the bitmap block in
no_drift, which only compared the two decoders and ran on cloud too.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
bitmap-text is folded into "bundle bitmap bitmap -o text"; the default stays
the compressed form. decode takes the same flag and defaults to text. The
text form starts with a "size=N context=C" header, and -o json renders size,
context and trees of the present fields and of the bool fields seen true and
false. The Python decoder prints the same header.

The presence test pins the JSON form and checks that decode reproduces it and
that re-encoding is byte-identical; validate_bitmap round-trips JSON on every
invariant config.

Co-authored-by: Isaac <no-reply@databricks.com>
Like acceptance/bundle/refschema: resources.<type>.* goes to
output/<type>.txt and everything else to output/root.txt. Each line carries
its bit, so a file still shows where its fields sit in the schema.

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

Co-authored-by: Isaac <no-reply@databricks.com>
app_lifecycle_started, cluster_lifecycle_started and
sql_warehouse_lifecycle_started took the value of whichever resource came
first in map order, so with one app started and another stopped the
reported value changed from run to run. They now report true if any
resource of the type sets started: true and false if any sets false, each
value once; a bundle whose resources agree still sends a single entry.

The fields become []bool, which changes their bitmap entries; the schema
is not released yet, so it is regenerated from scratch.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
The per-artifact and per-resource flags were []bool fields grown with
append. They are now BoolSet, which records the values a measurement took:
call sites read b.Telemetry.ArtifactFilesIsSet.SetBool(x), bool_values gets
each value taken once (true before false), and the bitmap gives the field a
presence bit plus its =true/=false bits, the same entries as any bool.

The lifecycle.started loops call SetBool per resource, which replaces the
startedValues helper. Telemetry bits are now set directly instead of through
a dyn conversion. The schema is not released yet, so it is regenerated.

Co-authored-by: Isaac <no-reply@databricks.com>
Initialize now marks the loaded config into a bitmap.Builder kept on the
bundle (replacing the UserConfig snapshot), and the Python mutator marks the
resources it adds. Fields holding a pure ${var.*} reference are kept in a side
set; at the end of Initialize each reference is evaluated against the
variables' final values and its value is marked in place. So a bool set
through a variable records its value (strings from --var or BUNDLE_VAR_* are
coerced like the loader does), and a complex variable records the fields
inside it. Bits are only ever added: an unresolved reference keeps its
presence bit.

bundle.target and bundle.environment are pruned: target selection sets them
on every bundle. The schema is unreleased, so it is regenerated.

The bitmap tests that need bundle.Telemetry move to an external test package,
since bundle now imports bitmap.

Co-authored-by: Isaac <no-reply@databricks.com>
use_legacy_run_as is now a *bool, so read it with config.IsExplicitlyEnabled.
An explicit false on such a field now survives loading, so the presence
fixture records F experimental.use_legacy_run_as; the comment about the gap
is updated.

Co-authored-by: Isaac <no-reply@databricks.com>
@denik
denik force-pushed the denik/bundle-bitmap branch from 6d41413 to e070c71 Compare November 9, 2026 15:53

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