Emit E_PROVISION_CONFLICT for uv sync resolution conflicts - #6479
Emit E_PROVISION_CONFLICT for uv sync resolution conflicts#6479rugpanov wants to merge 3 commits into
Conversation
`databricks environments setup-local` wrapped every `uv sync` failure as
E_PROVISION. The extension's recovery flow needs to tell a dependency-resolution
failure — the remote pins just written can't be satisfied against the user's
local dependencies — apart from a generic sync failure it can't fix by adjusting
constraints.
Classify a `uv sync` failure as the new E_PROVISION_CONFLICT when uv's stderr
carries its resolver banner ("No solution found when resolving dependencies");
every other sync failure keeps E_PROVISION. The failing phase (provision),
diskMutated=true, and the E_CANCELED reclassification are unchanged. Adds the
matching telemetry enum value and an acceptance golden that drives a real
setup-local run against a fake uv failing sync with the resolver banner.
Co-authored-by: Isaac <no-reply@databricks.com>
Three independent reviewers converged: matching uv's "No solution found" stderr classified every resolution failure — including an unavailable package, which relaxing constraints can't fix — as a conflict, broader than the ticket's "remote pins conflict with the user's dependencies" and misleading to consumers. Gate the code on the CLI's own detection instead: emit E_PROVISION_CONFLICT when a uv sync failure coincides with the merge phase's W_USER_CONSTRAINT_CONFLICT warning (a provable disjoint-version conflict), else keep E_PROVISION. Removes the stderr string-matching (and its brittleness / the errors-string-matching concern) entirely. Adds pipeline unit tests for the conflict and generic-failure paths; the acceptance golden and telemetry mapping are unchanged in outcome. Co-authored-by: Isaac <no-reply@databricks.com>
Make explicit in provision() that E_PROVISION_CONFLICT gating on the merge's W_USER_CONSTRAINT_CONFLICT signal can coincide with an unrelated sync failure — and that this is intentional: the warning proves a real conflict exists, so relaxing the pins is a necessary step regardless, and uv stays the source of truth for whether sync fails while the CLI's own detection classifies why. No behavior change. Raised in review (Codex/Claude), kept as-is per decision. Co-authored-by: Isaac <no-reply@databricks.com>
Approval status: pending
|
Why
databricks environments setup-localwrapped everyuv syncfailure asE_PROVISION. The VPEX extension's recovery flow needs to distinguish adependency version conflict — the project's dependencies can't be satisfied
against the pins this command wrote — from a generic sync failure it can't fix by
relaxing constraints (a build-backend error, a permissions problem, a transport
error, or an unavailable package). Constraints are already written at the point of
failure (merge precedes provision, so
error.diskMutated=true), which the recoveryflow relies on. Fixes DECO-28365.
What
E_PROVISION_CONFLICT(libs/localenv/result.go), emittedfrom the provision phase.
output. The merge phase already detects a provable version conflict between the
user's dependencies and the environment pins and records it as the
W_USER_CONSTRAINT_CONFLICTwarning (libs/localenv/warnings.go, PEP 440interval math on provably-disjoint ranges). When a
uv syncfailure coincideswith that warning, the failure is that conflict surfacing, so it is reported as
E_PROVISION_CONFLICT(libs/localenv/pipeline.go,hasConstraintConflictWarning).Every other sync failure keeps
E_PROVISION.requires-python mismatch (neither is a
W_USER_CONSTRAINT_CONFLICT) staysE_PROVISION, so a consumer never gets aconflictcode for a failure thatrelaxing constraints can't fix. It also needs no stderr string-matching.
provision),diskMutated=true, and theE_CANCELEDreclassification are unchanged.
PostProvision(pip seed) andEnsurePythonkeep their existing codes.
SetupLocalErrorCodeProvisionConflictand the mapping case(
cmd/environments/telemetry.go,libs/telemetry/protos/setup_local.go), keptexhaustive by the linter and
TestErrorCodeCoversLocalenv. A matching value inthe universe lumberjack proto should follow (ingestion ignores unknown values,
so the two PRs can land in either order).
Testing
libs/localenv/pipeline_test.go): auv syncfailure with amerge
W_USER_CONSTRAINT_CONFLICT→E_PROVISION_CONFLICT(
failurePhase=provision,diskMutated=true); auv syncfailure withoutit — even one whose stderr looks like a resolver error →
E_PROVISION. Bothcross-platform.
acceptance/localenv/provision-conflict/): a realsetup-localrun where the user pins
pip==24.0and the remote constraints pinpip<24, sothe merge flags the conflict; a fake
uvon PATH (thepsqlacceptanceprecedent — a real
uv syncconflict needs a specific managed Python installedoffline, which CI can't guarantee) fails
uv sync. The golden assertserror.code=E_PROVISION_CONFLICT,failurePhase=provision,diskMutated=true,and the
W_USER_CONSTRAINT_CONFLICTwarning. Windows-disabled like thepsqltests; the unit tests cover the logic cross-platform.
gofmt,go vet,golangci-lint(root module), andgo build ./...clean.This pull request and its description were written by Isaac.