Skip to content

[VPEX][5a] Add local-env package-manager interface, detection, and preflight#5850

Merged
rugpanov merged 2 commits into
mainfrom
dbconnect/05a-pkgmanager
Jul 13, 2026
Merged

[VPEX][5a] Add local-env package-manager interface, detection, and preflight#5850
rugpanov merged 2 commits into
mainfrom
dbconnect/05a-pkgmanager

Conversation

@rugpanov

@rugpanov rugpanov commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Why

  • PR [VPEX][5/8] Add local-env pipeline, detection, and package-manager interface #5828 ([VPEX][5/8]) reads as +3,466 / 15 files on GitHub, but that is an artifact: PRs 1–4 were squash-merged into main while dbconnect/05-pipeline still sits on the pre-merge parent, so GitHub re-counts all of the already-merged code. The genuinely-new content in that layer is +1,165 / 5 files.
  • This splits that real delta at its one clean dependency seam. This PR is the leaf half: the PackageManager interface, manager detection, and the writability preflight — none of which reference the pipeline orchestrator.

What

  • pkgmanager.go — the PackageManager interface the pipeline provisions through (implemented by the uv backend in a later PR).
  • detect.go — uv-vs-not-uv detection (biased toward uv, whose native project file is the pyproject.toml this command drives), the non-blaming guidance message shown for an unsupported manager, and the ensureWritable preflight.
  • The pyprojectFile constant moves here from pipeline.go, since detection is its first consumer.

Testing strategy

  • detect_test.go covers the detection matrix (greenfield, uv lock, plain pyproject, conda/pip precedence), ensureWritable on a writable and a non-existent dir, and the unsupported-manager guidance message.
  • Gates: go build, go test, golangci-lint (0 issues), deadcode, gofmt — all green.

About this stack

This is one of a series of small, stacked PRs that together add the databricks local-env python sync command. It supersedes the pipeline half of #5828, split further at the interface/detection seam. Review bottom-up.

This PR and #5b (the six-phase pipeline orchestrator, stacked on this one) together replace #5828.

This pull request and its description were written by Isaac.

@eng-dev-ecosystem-bot

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

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: f24c320

Run: 28951586571

Env 🟨​KNOWN 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 4 4 230 1069 4:03
💚​ aws windows 4 4 232 1067 4:13
💚​ aws-ucws linux 4 4 314 987 7:02
💚​ aws-ucws windows 4 4 316 985 4:46
💚​ azure linux 4 4 230 1068 4:05
💚​ azure windows 4 4 232 1066 3:58
💚​ azure-ucws linux 4 4 316 984 7:33
🟨​ azure-ucws windows 1 1 4 318 982 9:44
💚​ gcp linux 4 4 229 1070 3:52
💚​ gcp windows 4 4 231 1068 4:16
8 interesting tests: 4 SKIP, 3 RECOVERED, 1 KNOWN
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 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 🟨​K 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/root 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/subdir 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
Top 6 slowest tests (at least 2 minutes):
duration env testname
3:23 gcp windows TestAccept
3:20 aws windows TestAccept
3:09 aws-ucws windows TestAccept
3:02 azure windows TestAccept
3:00 azure-ucws windows TestAccept
2:01 azure-ucws windows TestAccept/bundle/deploy/mlops-stacks/DATABRICKS_BUNDLE_ENGINE=terraform

Split from the pipeline layer so the PackageManager seam (implemented by
the uv backend in a later PR), manager detection, and the writability
preflight land as a small, independently reviewable unit.

- pkgmanager.go: the PackageManager interface the pipeline provisions through.
- detect.go: uv-vs-not-uv detection (biased toward uv, whose native project
  file is the pyproject.toml this command drives), the non-blaming guidance
  message for unsupported managers, and the ensureWritable preflight.

Co-authored-by: Isaac
@rugpanov rugpanov force-pushed the dbconnect/05a-pkgmanager branch from cb166cb to f24c320 Compare July 8, 2026 14:44
@rugpanov rugpanov temporarily deployed to test-trigger-is July 8, 2026 14:44 — with GitHub Actions Inactive
@rugpanov rugpanov temporarily deployed to test-trigger-is July 8, 2026 14:44 — with GitHub Actions Inactive

@anton-107 anton-107 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving. Clean leaf of the stack: detectManager is pure-fs with no telemetry (matches its doc), the uv-bias logic is well-reasoned and fully table-tested, and ensureWritable + managerGuidance are covered. PackageManager interface is small and well-documented (the PostProvision/pip-seeding comment captures a real VS Code quirk). No findings.

@rugpanov rugpanov added this pull request to the merge queue Jul 13, 2026
@rugpanov rugpanov temporarily deployed to test-trigger-is July 13, 2026 09:34 — with GitHub Actions Inactive
@rugpanov rugpanov temporarily deployed to test-trigger-is July 13, 2026 09:34 — with GitHub Actions Inactive
Merged via the queue into main with commit f7c9cee Jul 13, 2026
23 checks passed
@rugpanov rugpanov deleted the dbconnect/05a-pkgmanager branch July 13, 2026 09:49
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: f7c9cee

Run: 29240588827

Env ❌​FAIL 🟨​KNOWN 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 4 4 529 1010 40:46
❌​ aws windows 6 1 4 3 4 476 1023 59:00
❌​ aws-ucws linux 11 1 2 5 2 990 820 172:52
❌​ aws-ucws windows 11 1 2 5 2 932 838 185:00
🔄​ azure linux 4 3 4 520 1011 48:45
💚​ azure windows 4 4 480 1024 55:11
🔄​ azure-ucws linux 3 5 2 896 855 145:47
🔄​ azure-ucws windows 2 4 2 840 873 151:34
💚​ gcp linux 4 4 514 1016 54:19
💚​ gcp windows 4 4 471 1029 60:42
37 interesting tests: 17 FAIL, 15 flaky, 2 RECOVERED, 2 SKIP, 1 KNOWN
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 🟨​K 🟨​K 💚​R 💚​R 🔄​f 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 💚​R 💚​R 🙈​S 🙈​S 💚​R 💚​R 🙈​S 🙈​S
🔄​ TestAccept/bundle/resources/dashboards/change-name ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/resources/dashboards/change-name/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/resources/dashboards/change-name/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p
❌​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions ✅​p ❌​F ✅​p ✅​p 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s
❌​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions ✅​p ❌​F ✅​p ✅​p 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s
❌​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct ✅​p ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ❌​F ✅​p ✅​p
❌​ TestAccept/bundle/resources/postgres_databases/live_errors/missing_role 🙈​s 🙈​s ❌​F ❌​F 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s
❌​ TestAccept/bundle/resources/postgres_databases/live_errors/missing_role/DATABRICKS_BUNDLE_ENGINE=direct ❌​F ❌​F
❌​ TestAccept/bundle/resources/postgres_endpoints/basic 🙈​s 🙈​s ❌​F ❌​F 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s
❌​ TestAccept/bundle/resources/postgres_endpoints/basic/DATABRICKS_BUNDLE_ENGINE=direct ❌​F ❌​F
❌​ TestAccept/bundle/resources/postgres_endpoints/basic/DATABRICKS_BUNDLE_ENGINE=terraform ❌​F ❌​F
❌​ TestAccept/bundle/resources/postgres_endpoints/replace_existing 🙈​s 🙈​s ❌​F ❌​F 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s
❌​ TestAccept/bundle/resources/postgres_endpoints/replace_existing/DATABRICKS_BUNDLE_ENGINE=direct ❌​F ❌​F
❌​ TestAccept/bundle/resources/postgres_endpoints/replace_existing/DATABRICKS_BUNDLE_ENGINE=terraform ❌​F ❌​F
❌​ TestAccept/bundle/resources/postgres_endpoints/update_autoscaling 🙈​s 🙈​s ❌​F ❌​F 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s 🙈​s
❌​ TestAccept/bundle/resources/postgres_endpoints/update_autoscaling/DATABRICKS_BUNDLE_ENGINE=direct ❌​F ❌​F
❌​ TestAccept/bundle/resources/postgres_endpoints/update_autoscaling/DATABRICKS_BUNDLE_ENGINE=terraform ❌​F ❌​F
🔄​ TestAccept/bundle/resources/secret_scopes/basic ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/resources/secret_scopes/basic/DATABRICKS_BUNDLE_ENGINE=terraform ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p
💚​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 💚​R 💚​R 🙈​S 🙈​S 💚​R 💚​R 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🔄​ TestAccept/bundle/templates/default-python/combinations/classic/DATABRICKS_BUNDLE_ENGINE=direct/DLT=no/NBOOK=yes/PY=no/READPLAN= ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/templates/default-python/combinations/classic/DATABRICKS_BUNDLE_ENGINE=direct/DLT=no/NBOOK=yes/PY=yes/READPLAN=1 ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/templates/default-python/combinations/classic/DATABRICKS_BUNDLE_ENGINE=terraform/DLT=no/NBOOK=no/PY=no/READPLAN= ✅​p ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/templates/default-python/combinations/classic/DATABRICKS_BUNDLE_ENGINE=terraform/DLT=no/NBOOK=no/PY=yes/READPLAN= ✅​p ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/templates/default-python/combinations/classic/DATABRICKS_BUNDLE_ENGINE=terraform/DLT=no/NBOOK=yes/PY=no/READPLAN= ✅​p ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/templates/default-python/integration_classic ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestAccept/bundle/templates/default-python/integration_classic/DATABRICKS_BUNDLE_ENGINE=terraform/UV_PYTHON=3.11 ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🔄​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 🔄​f 💚​R 💚​R 💚​R 💚​R 💚​R
🔄​ TestFetchRepositoryInfoAPI_FromRepo/root 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 🔄​f 💚​R 💚​R
🔄​ TestFetchRepositoryInfoAPI_FromRepo/subdir 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 🔄​f 💚​R 💚​R
Top 50 slowest tests (at least 2 minutes):
duration env testname
12:39 gcp linux TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
12:22 gcp windows TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
11:44 gcp windows TestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
11:05 gcp linux TestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
10:00 gcp windows TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
9:44 gcp windows TestAccept/bundle/resources/clusters/deploy/local_ssd_count/DATABRICKS_BUNDLE_ENGINE=direct
9:28 azure windows TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
9:04 aws-ucws windows TestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
8:37 aws-ucws linux TestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
8:34 aws-ucws windows TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
8:29 azure-ucws linux TestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
8:09 azure windows TestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
8:08 aws windows TestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:54 azure linux TestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:47 azure-ucws windows TestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:41 azure linux TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:40 aws-ucws linux TestAccept/bundle/config-remote-sync/multiple_resources/DATABRICKS_BUNDLE_ENGINE=direct
7:26 gcp linux TestAccept/bundle/resources/clusters/deploy/local_ssd_count/DATABRICKS_BUNDLE_ENGINE=direct
7:18 azure-ucws windows TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:17 aws linux TestAccept/bundle/resources/apps/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
7:16 azure-ucws linux TestAccept/bundle/config-remote-sync/multiple_resources/DATABRICKS_BUNDLE_ENGINE=terraform
6:51 gcp windows TestAccept/bundle/resources/clusters/deploy/update-after-create/DATABRICKS_BUNDLE_ENGINE=terraform
6:46 azure windows TestAccept
6:34 gcp windows TestAccept
6:33 azure-ucws linux TestAccept/bundle/templates/default-python/combinations/classic/DATABRICKS_BUNDLE_ENGINE=direct/DLT=no/NBOOK=yes/PY=yes/READPLAN=
6:32 azure-ucws windows TestAccept
6:10 aws-ucws linux TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
6:09 aws linux TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
6:02 azure-ucws linux TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
6:01 aws windows TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
6:00 aws-ucws windows TestAccept/bundle/templates/default-python/combinations/serverless/DATABRICKS_BUNDLE_ENGINE=terraform/DLT=yes/NBOOK=yes/PY=yes/READPLAN=
5:54 azure-ucws windows TestAccept/bundle/templates/default-python/integration_classic/DATABRICKS_BUNDLE_ENGINE=terraform/UV_PYTHON=3.11
5:51 aws-ucws linux TestAccept/bundle/resources/clusters/lifecycle-started/DATABRICKS_BUNDLE_ENGINE=direct
5:35 gcp linux TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
5:32 azure-ucws windows TestAccept/bundle/resources/registered_models/basic/DATABRICKS_BUNDLE_ENGINE=terraform
5:21 gcp windows TestAccept/bundle/resources/apps/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
5:20 aws-ucws windows TestAccept/bundle/resources/registered_models/basic/DATABRICKS_BUNDLE_ENGINE=terraform
5:05 aws-ucws windows TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
5:01 aws-ucws windows TestAccept/bundle/templates/default-python/combinations/serverless/DATABRICKS_BUNDLE_ENGINE=terraform/DLT=no/NBOOK=yes/PY=yes/READPLAN=
4:59 azure-ucws windows TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
4:50 azure-ucws windows TestAccept/bundle/resources/registered_models/basic/DATABRICKS_BUNDLE_ENGINE=direct
4:50 azure-ucws linux TestAccept/bundle/config-remote-sync/multiple_resources/DATABRICKS_BUNDLE_ENGINE=direct
4:48 gcp linux TestAccept/bundle/resources/apps/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
4:47 aws-ucws windows TestAccept/bundle/deploy/spark-jar-task/DATABRICKS_BUNDLE_ENGINE=direct
4:41 azure-ucws windows TestAccept/bundle/templates/default-python/combinations/classic/DATABRICKS_BUNDLE_ENGINE=terraform/DLT=yes/NBOOK=yes/PY=yes/READPLAN=
4:40 azure-ucws linux TestAccept/bundle/resources/secret_scopes/permissions/DATABRICKS_BUNDLE_ENGINE=terraform
4:39 gcp windows TestAccept/bundle/resources/apps/lifecycle-started-omitted/DATABRICKS_BUNDLE_ENGINE=direct
4:38 aws-ucws linux TestAccept/bundle/templates/default-python/combinations/classic/DATABRICKS_BUNDLE_ENGINE=terraform/DLT=no/NBOOK=yes/PY=yes/READPLAN=
4:36 aws-ucws linux TestAccept/bundle/resources/apps/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct
4:34 azure-ucws linux TestAccept/bundle/resources/clusters/lifecycle-started-toggle/DATABRICKS_BUNDLE_ENGINE=direct

bradleyjamrozik-origindigital pushed a commit to Origin-Digital-LLC/databricks-cli that referenced this pull request Jul 13, 2026
…5851)

## Why

- The earlier layers (resolve / fetch / merge) need an orchestrator that
runs them in order, reports structured per-phase status, and provisions
the environment — without mutating disk in `--check` dry-run mode.
- This is the core half of the split described in databricks#5850: the six-phase
pipeline itself, stacked on the package-manager/detection layer.

## What

- **`pipeline.go`** — the six-phase orchestrator (`preflight → resolve →
fetch → merge → provision → validate`). It records per-phase status into
`Result` and returns typed `PipelineError`s carrying `FailurePhase` and
`DiskMutated`. Under `--check` it computes and reports the plan (with a
diff) and performs no writes, skipping the writability probe and
package-manager availability (neither is needed to compute the plan).
- The merge base is the **live `pyproject.toml`**. `MergeManaged`
rewrites only the three managed regions and is idempotent on its own
output, so a re-run preserves edits the user made between syncs. The
`.bak` is a one-time safety copy of the pre-sync original (created only
when none exists, on the first sync of an existing project); an
unreadable or unstattable existing file fails loudly rather than being
misread as greenfield and overwritten.
- `constraints-only` stops *managing* the databricks-connect pin rather
than removing it: a greenfield project renders `dev = []` (no
databricks-connect), and an existing project that already pins
databricks-connect keeps its pin untouched.

## Testing strategy

- End-to-end unit tests of the phase machine against a fake
`PackageManager` + stub compute + `httptest` server: `--check` mutates
nothing (even on a read-only dir / without a package manager) and
reports a plan that matches a real re-run (no spurious backup, empty
diff when idempotent), greenfield vs. existing, the merge basing on the
live file so between-sync edits survive, backup safety on
unreadable/unstattable files, constraints-only behavior, preflight exits
(`E_MANAGER_UNSUPPORTED` / `E_UV_MISSING`), and phase/error attribution
(`pipeline_test.go`).
- Gates: `go build`, `go test`, `golangci-lint` (0 issues), `deadcode`,
`gofmt` — all green.

---

## About this stack

**Review bottom-up.** This PR targets databricks#5850 as its base, so its diff
shows only the pipeline layer.

This PR and databricks#5850 together supersede databricks#5828.

This pull request and its description were written by Isaac.
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.

3 participants