Skip to content

Consolidate bundle schema annotations into one tree-structured file#5574

Draft
pietern wants to merge 7 commits into
mainfrom
rethink-annotations
Draft

Consolidate bundle schema annotations into one tree-structured file#5574
pietern wants to merge 7 commits into
mainfrom
rethink-annotations

Conversation

@pietern

@pietern pietern commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Changes

The bundle JSON schema annotations move from three type-name-keyed YAML files to a single bundle/internal/schema/annotations.yml structured like the bundle configuration tree:

  • annotations_openapi.yml (~7k lines of derived data) is deleted. The generator now computes those annotations in memory from .codegen/cli.json on every run, so upstream docs are never materialized in the repo.
  • annotations_openapi_overrides.yml and the old annotations.yml are consolidated into the new annotations.yml. A node documents one field inline; type: documents the type the field's value resolves to (for map and sequence fields: each entry) and carries enum values — these docs land on the type's shared $defs entry; fields: holds the block of that type's fields (maps/sequences unwrapped). Each type is expanded exactly once, at its first occurrence in struct declaration order, so shared types (e.g. everything under targets) are documented in one place.
  • Annotations absent from the file inherit upstream docs from cli.json; entries in the file override them; description: PLACEHOLDER marks fields with no docs anywhere.
  • task generate-schema keeps the file in sync via reflection over the config types: placeholders are added for new undocumented fields, and entries whose field or type no longer exists are dropped with a warning. The file's structure is validated against the same jsonschema.FromType walk that generates the schema, so it cannot drift.
  • The separate generate-annotations task is gone; the generator takes the cli.json path as a required argument (the DATABRICKS_CLI_JSON env var is removed).

Why

The type-name-keyed files didn't show where a field lives in the configuration, and most of their content was a copy of cli.json data that went stale between regenerations. With a single structured file there is exactly one place to write CLI-owned docs and overrides, it reads like the config it documents, and everything inherited from cli.json stays out of the repo.

Tests

  • bundle/schema/jsonschema.json and jsonschema_for_docs.json are byte-identical to main after regeneration; the annotations file rewrite is byte-idempotent across runs (this is also asserted in CI by the existing drift gate and the docs workflow).
  • New unit tests cover the type graph (declaration order, embedding, map/slice unwrap, cycles) and the file codec (golden output, round-trip byte stability, unknown and detached entry detection).
  • TestRequiredAnnotationsForNewFields and TestNoDetachedAnnotations are rewritten for the new format. Migration dropped 23 entries that referenced fields no longer present in the config (verified against the structs).
  • ./task generate-check, full lint, fmt, checks, and test pass locally.

This pull request and its description were written by Isaac.

Drop the checked-in annotations_openapi.yml: the schema generator now
derives those annotations from .codegen/cli.json in memory on every run.
Merge annotations.yml and annotations_openapi_overrides.yml into a single
annotations.yml whose structure mirrors the bundle configuration tree.
Docs absent from the file inherit from cli.json; entries override them.

The generated jsonschema.json and jsonschema_for_docs.json are unchanged.

Co-authored-by: Isaac
@pietern pietern temporarily deployed to test-trigger-is June 12, 2026 14:02 — with GitHub Actions Inactive
@pietern pietern temporarily deployed to test-trigger-is June 12, 2026 14:02 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown
Contributor

Approval status: pending

/bundle/ - needs approval

13 files changed
Suggested: @janniklasrose
Also eligible: @denik, @shreyas-goenka, @andrewnester, @lennartkats-db, @anton-107

General files (require maintainer)

Files: .agent/rules/auto-generated-files.md, Taskfile.yml
Based on git history:

  • @simonfaltum -- recent work in bundle/internal/schema/, .agent/rules/

Any maintainer (@andrewnester, @anton-107, @denik, @shreyas-goenka, @simonfaltum, @renaudhartert-db) can approve all areas.
See OWNERS for ownership rules.

@pietern pietern marked this pull request as draft June 12, 2026 14:04
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 4f4fe2c

Run: 27460464519

Env ❌​FAIL 🟨​KNOWN 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
🔄​ aws linux 4 3 15 264 977 9:34
🟨​ aws windows 7 15 266 975 16:58
💚​ aws-ucws linux 7 15 360 891 7:19
💚​ aws-ucws windows 7 15 362 889 10:37
❌​ azure linux 28 1 17 239 975 15:22
🔄​ azure windows 3 17 267 973 13:18
💚​ azure-ucws linux 1 17 365 887 7:22
💚​ azure-ucws windows 1 17 367 885 12:23
💚​ gcp linux 1 17 263 978 7:17
💚​ gcp windows 1 17 265 976 10:21
52 interesting tests: 28 FAIL, 15 SKIP, 7 KNOWN, 2 flaky
Test Name aws linux aws windows aws-ucws linux aws-ucws windows azure linux azure windows azure-ucws linux azure-ucws windows gcp linux gcp windows
🟨​ TestAccept 💚​R 🟨​K 💚​R 💚​R 🟨​K 🔄​f 💚​R 💚​R 💚​R 💚​R
❌​ TestAccept/bundle/deploy/mlops-stacks ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/deploy/mlops-stacks/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/deployment/bind/alert 🙈​s 🙈​s 🙈​s 🙈​s ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/deployment/bind/alert/DATABRICKS_BUNDLE_ENGINE=direct ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
❌​ TestAccept/bundle/resources/apps/inline_config ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/jobs/check-metadata ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/jobs/check-metadata/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/jobs/check-metadata/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/jobs/shared-root-path ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/jobs/shared-root-path/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/jobs/shared-root-path/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
🙈​ TestAccept/bundle/resources/permissions 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
❌​ TestAccept/bundle/resources/permissions/dashboards/create ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p 🙈​s 🙈​s
❌​ TestAccept/bundle/resources/permissions/dashboards/create/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/permissions/dashboards/create/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions 💚​R 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🔄​f 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🔄​f 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions 💚​R 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🔄​f 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🔄​f 🟨​K 💚​R 💚​R
🙈​ TestAccept/bundle/resources/postgres_branches/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/replace_existing 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/update_protected 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/without_branch_id 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_projects/update_display_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/synced_database_tables/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/grants/select 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
❌​ TestAccept/bundle/run_as/job_default ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/run_as/job_default/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/basic ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/basic/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/basic/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/error ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/error/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/error/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/pipeline-crud ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/pipeline-crud/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/pipeline-crud/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/workspace-file-io ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/workspace-file-io/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/selftest/record_cloud/workspace-file-io/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p ✅​p ❌​F ✅​p ✅​p ✅​p ✅​p ✅​p
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
Top 24 slowest tests (at least 2 minutes):
duration env testname
6:02 azure-ucws windows TestAccept
5:00 aws-ucws windows TestAccept
4:59 gcp windows TestAccept
4:27 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:57 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:54 gcp windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:43 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:40 gcp linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:26 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:25 azure windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:23 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:17 aws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:12 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:11 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:02 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
3:01 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
3:01 aws-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:52 gcp linux TestAccept
2:50 azure-ucws linux TestAccept
2:48 azure-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=terraform
2:46 aws-ucws linux TestAccept
2:42 aws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:41 azure-ucws windows TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct
2:40 aws-ucws linux TestAccept/bundle/resources/apps/inline_config/DATABRICKS_BUNDLE_ENGINE=direct

Replace the "_" entry inside "fields" with an explicit "type" key on the
node, sibling to "fields". For map and sequence fields it documents each
entry; for scalar fields it documents the value's type (enum values live
here). Purely a file-format spelling change; the in-memory representation
and the generated schema are unchanged.

Co-authored-by: Isaac
Fold the near-identical inline-descriptor and type-docs serialization
paths into one descriptorToMap helper and hoist the shared key order to a
package var. Document RootTypeKey as the in-memory sentinel. No change to
the generated annotations file or schema.

Co-authored-by: Isaac
@pietern pietern temporarily deployed to test-trigger-is June 13, 2026 06:32 — with GitHub Actions Inactive
@pietern pietern temporarily deployed to test-trigger-is June 13, 2026 06:32 — with GitHub Actions Inactive
The in-memory annotations keyed each type's docs by field name plus a
magic "_" entry for the type itself, forcing "_" to dodge real field
names (config has fields named type, fields, description). Model it
instead as TypeAnnotation{Self, Fields}: Self is the type's own docs
(applied to its $defs entry; also where enum values live), Fields is the
per-field docs. The "_" sentinel and RootTypeKey are gone.

No change to the generated annotations file or schema.

Co-authored-by: Isaac
@pietern pietern temporarily deployed to test-trigger-is June 13, 2026 06:41 — with GitHub Actions Inactive
@pietern pietern temporarily deployed to test-trigger-is June 13, 2026 06:41 — with GitHub Actions Inactive
pietern added 2 commits June 13, 2026 09:30
structFieldNames re-implemented the generator's readonly/internal/
exported/json-tag skip rules and then cross-checked the result against
the emitted schema. The schema's property set is already authoritative,
so order the names by struct declaration and keep only those the schema
emitted; reflection now supplies order alone. A count check still catches
a struct walk that fails to reach a property.

Co-authored-by: Isaac
A config field named "type" (artifacts.*.type, variables.*.type) was told
apart from the structural type-docs key only by nesting level. Prefix the
two structural keys with "$" — matching the JSON-Schema convention this
file documents — so they can never be confused with or collide with a
field of the same name, which always appears as a bare key inside
"$fields". Also tidy the saver: a takeSelf accessor mirrors takeField, and
the ordering line numbers are named constants.

No change to the generated schema.

Co-authored-by: Isaac
@pietern pietern temporarily deployed to test-trigger-is June 13, 2026 07:30 — with GitHub Actions Inactive
@pietern pietern temporarily deployed to test-trigger-is June 13, 2026 07:30 — with GitHub Actions Inactive
It wrapped clijson.Parse with an empty-schemas check and was called once.
Fold it into generateSchema and drop cli_json.go.

Co-authored-by: Isaac
@pietern pietern temporarily deployed to test-trigger-is June 13, 2026 07:32 — with GitHub Actions Inactive
@pietern pietern temporarily deployed to test-trigger-is June 13, 2026 07:32 — with GitHub Actions Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants