Skip to content

release: 2026.04.1#77

Merged
discreteds merged 64 commits into
mainfrom
release/2026.04.1
Apr 18, 2026
Merged

release: 2026.04.1#77
discreteds merged 64 commits into
mainfrom
release/2026.04.1

Conversation

@discreteds

Copy link
Copy Markdown
Member

Summary

Production release cut from develop. First production bump since the 2026.04.0 RC.

Changes since last main merge (2026.04.0 RC)

⚠️ Upstream gate

Do not publish this release until mountainash-settings PR #36 (v26.4.2 hotfix) merges and is released. Pre-v26.4.2, import mountainash_settings crashes in any venv without pytest installed (module-top import pytest in profiles/invariants.py). Every mountainash_data production deploy imports settings transitively, so the hotfix must ship first or prod deploys break on import.

Test plan

  • mountainash-settings v26.4.2 merged + tagged
  • hatch run test:test tests/test_unit/ green on this branch
  • CI build + SBOM generation green
  • Reviewer: confirm version bump is correct (2026.04.0 RC → 2026.04.1 production)

Post-merge

  • Tag v2026.04.1
  • Merge main back into develop (keep downstream CI checkouts in sync)

🤖 Generated with Claude Code

discreteds and others added 30 commits April 15, 2026 21:30
Defines scope, source precedence, per-backend report structure,
and index for auditing 11 backend settings classes against their
authoritative driver/Ibis/vendor specs. Report-only; fixes handled
in separate per-backend cycles.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
13 tasks: one per backend (11) + pyiceberg_rest + index summary
fill-in. Each task is self-contained with concrete file paths,
source URLs tagged by precedence, and report schema references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Descriptor-based backend registry with typed AuthSpec discriminated union
and optional per-backend adapter for composite driver mappings. Consumes
audit findings (docs/superpowers/specs/2026-04-15-settings-audit/) to guide
parameter tiering and bug fixes carried into the refactor.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
22-task plan covering Phases 1-3 of the registry redesign: scaffolding
(ConnectionProfile + descriptor + AuthSpec union + registry), per-backend
migrations in cheap->hard order carrying audit fixes, and consumer-side
call-site updates. Phase 4 (residual per-backend audit sweeps) is
intentionally deferred to follow-up plans.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add the core primitive data structures for the settings registry refactor:
- MISSING sentinel for required (no-default) fields
- ParameterSpec: frozen dataclass describing one backend field
- BackendDescriptor: frozen dataclass describing a complete backend

These are plain frozen dataclasses with no pydantic or runtime behavior,
establishing the foundation for descriptor-driven settings configuration.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Remove unused `field` import from descriptor.py
- Remove unused `Literal` and `Optional` imports from test file
- Tighten pytest.raises(Exception) to FrozenInstanceError for freeze tests
- Replace tautology test_parameter_spec_tier_must_be_valid with:
  - test_parameter_spec_accepts_advanced_tier (positive test)
  - test_missing_sentinel_is_falsy_and_singleton (MISSING behavior test)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add 11 auth variants covering all authentication patterns needed across
database backends (none, password, token, oauth2, service account, IAM,
Windows, Azure AD, Kerberos, certificate). Each variant is a frozen
pydantic model with a discriminator kind field, enabling clean type-safe
union composition in downstream connection profiles.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Drop kind: str from AuthSpec base (fixes Pyright override warnings)

- Add frozen + extra=forbid contract tests

- Remove unused AuthSpec import in test file

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Document _iam empty-dict return (ambient AWS credentials)
- Add OAuth2 token-wins, OAuth2 empty, IAM empty regression tests

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Introduces ConnectionProfile, a pydantic v2 base class that uses
__pydantic_init_subclass__ to materialize BackendDescriptor parameters
and auth_modes into validated pydantic fields at subclass definition
time, wiring up to_driver_kwargs / to_connection_string generically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Clarify to_driver_kwargs adapter contract (adapter owns the pipeline)
- URL-encode username/password in to_connection_string
- Document the MountainAshBaseSettings setattr bypass
- Add tests: adapter-replaces, adapter-fresh, transform, URL-encoded password
- Source adapter via __dict__ lookup (fixes Pyright call-site arity)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rewrite SQLiteAuthSettings as a two-line shell subclass of ConnectionProfile
- Replace old BaseDBAuthSettings inheritance with descriptor-driven config
- Add SQLITE_DESCRIPTOR with auth, parameters (DATABASE, TYPE_MAP), and ibis mapping
- Register SQLITE_DESCRIPTOR via @register decorator
- Add comprehensive test suite: test_minimal_construction, test_database_memory,
  test_to_driver_kwargs_memory, test_to_driver_kwargs_none_database_dropped,
  test_type_map_optional
- Verify 10 parametric descriptor invariants for sqlite pass via registry

This is the template migration for all 11 subsequent backends (Tasks 8-18).
Legacy consumer tests in tests/test_unit/databases/ fail as expected; Task 20
updates all call sites to use the new ConnectionProfile API.
discreteds and others added 26 commits April 16, 2026 11:27
…ixes

- Rewrite mssql.py with MSSQLDriver/MSSQLEncryption StrEnum and registry decorator
- Add mssql.py adapter with comprehensive auth dispatch (Password/Windows/AzureAD)
- Instance-name folding (host\instance), encryption flags, MARS support
- Test audit fixes: AZURE_MANAGED_IDENTITY/MSI_ENDPOINT, args['server'] KeyError
- 5 new specific tests + 10 invariant tests (all passing, no __setattr__ override needed)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…egion regex

Task 17: Redshift settings migration complete. Replaced BaseDBAuthSettings
with descriptor-driven ConnectionProfile. Added RedshiftSSLMode StrEnum
(default VERIFY_FULL). Widened region regex to accept GovCloud (us-gov-west-1).
Widened role ARN regex to accept non-commercial partitions (arn:aws-us-gov:,
arn:aws-cn:). Implemented IAMAuth/PasswordAuth adapter that properly routes
AWS credentials and session tokens. Plumbed CLUSTER_READ_ONLY and WORKGROUP_NAME.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Task 20 of the settings-registry refactor. All call sites outside settings/
now use the new ConnectionProfile API: to_driver_kwargs(), to_connection_string(),
and provider_type. Key changes:

- core/connection.py: BaseDBAuthSettings → ConnectionProfile, db_provider_type →
  provider_type, get_connection_kwargs delegates to to_driver_kwargs() with legacy
  fallback
- backends/ibis/connection.py: provider_type rename (12 subclasses), new
  connect_default code path uses ibis.<dialect>.connect(**driver_kwargs) for
  ConnectionProfile instances, filters empty lists (e.g. extensions=[]) that ibis
  rejects
- backends/iceberg/connection.py: provider_type rename, connect_default uses
  to_driver_kwargs() for ConnectionProfile instances
- core/factories/settings_factory.py: auto-injects auth=NoAuth() for NoAuth-only
  ConnectionProfile subclasses in from_backend_type()
- All test files: BaseDBAuthSettings → ConnectionProfile imports, auth=NoAuth()
  added to all SettingsParameters.create() kwargs that call connect()

All 483 unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The validator field on ParameterSpec was declared but never consumed
by ConnectionProfile.__pydantic_init_subclass__. Now wired via
pydantic v2's Annotated[type, AfterValidator(fn)] pattern.

This enables descriptor-level validation (rejection) without needing
explicit @field_validator(check_fields=False) on each shell class.
Backends like DuckDB, BigQuery, and Redshift that already declared
validator= on their ParameterSpecs now get automatic validation.

Note: due to MountainAshBaseSettings' setattr-bypass path,
validators work for rejection but not for value transformation —
the raw kwarg overwrites the validated value post-construction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9 tasks: rewire mountainash-data to import descriptor/profile/auth
machinery from mountainash-settings.profiles + mountainash-settings.auth,
replace module-level REGISTRY with per-domain DATABASES_REGISTRY,
preserve external API byte-for-byte, collapse test_descriptors_invariants
to the one-line shared helper.

Depends on Phase 1 (profiles-scaffolding) being merged and released.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
refactor(settings): descriptor-based registry — 12 backends migrated
Replace the fat local ConnectionProfile/registry/descriptor/auth stack with
thin wrappers over mountainash_settings.profiles primitives. Deletes the local
descriptor.py (BackendDescriptor, ParameterSpec, MISSING) and the entire auth/
sub-package; those now live in the upstream mountainash-settings library.
Introduces DATABASES_REGISTRY (Registry instance) and updates register/
get_descriptor/get_settings_class to delegate to it. Adds a _RegistryDictView
backwards-compat alias for existing REGISTRY imports. Intentionally breaks
imports across the 12 per-backend files — Task 3 fixes them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… auth

- Adapter files: `from mountainash_data.core.settings.auth import` →
  `from mountainash_settings.auth import`; rename `_default_driver_kwargs()`
  → `_default_kwargs()` and `_auth_to_driver_kwargs()` → `_auth_kwargs()`
  across 7 adapter files.
- Create `settings/descriptor.py` with typed `BackendDescriptor` subclass
  (extends `ProfileDescriptor` with `default_port`, `connection_string_scheme`,
  `ibis_dialect`, `rides_on` fields) so per-backend files keep typed field access.
- Per-backend files: import now routes through `.descriptor` → `mountainash_settings.profiles`.
- `settings/auth/` compatibility shim package: re-exports all auth primitives
  from `mountainash_settings.auth` so existing `from mountainash_data.core.settings.auth
  import X` call sites continue to work.
- `registry.py`: expose `_snapshot_for_tests` / `_reset_for_tests` module-level
  wrappers delegating to `DATABASES_REGISTRY`.
- `settings/__init__.py`: auth re-exports now pull from `mountainash_settings.auth`
  directly.

Result: 234 passed, 1 skipped (test_adapter_replaces_pipeline_output uses old
`_default_driver_kwargs()` name in test adapter — Task 7 territory).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Remove test_auth.py and test_auth_dispatch.py (coverage moved to
mountainash-settings). Rewrite descriptor/profile/registry tests to
cover only data-specific behaviour (BackendDescriptor fields,
to_driver_kwargs(), to_connection_string(), DATABASES_REGISTRY wrapper).
Fixes 1 failing test that called the removed _default_driver_kwargs().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…otion

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
feat(settings): Phase 2 — migrate to mountainash-settings.profiles + auth
The override coerced MODE strings to PySparkMode enum because the
pre-fix parent __init__ called update_settings_from_dict() which
used raw setattr, bypassing pydantic validators.

As of mountainash-settings v26.4.1, MountainAshBaseSettings sets
model_config["validate_assignment"] = True and the redundant
update_settings_from_dict call in __init__ is gone. Every
setattr on an instance — including in __init__, SettingsManager
runtime overrides, and apply_runtime_overrides — now runs the
field's pydantic validator pipeline, which handles StrEnum
coercion natively.

Verified in dev env with mountainash-settings 26.4.2: both
PySparkAuthSettings(MODE='batch', ...) and s.MODE = 'streaming'
produce PySparkMode enum instances without this override.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Zero imports in src/ or tests/. Superseded by
ConnectionProfile.to_connection_string() on the new descriptor
pattern. Flagged in the mountainash-data legacy-cleanup backlog
as safe-to-delete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chore(settings): retire PySpark __setattr__ override and orphaned templates.py
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
6 Security Hotspots

See analysis details on SonarQube Cloud

@codecov

codecov Bot commented Apr 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.49682% with 179 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.79%. Comparing base (fea4901) to head (c95c439).
⚠️ Report is 108 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...nash_data/core/settings/adapters/pyiceberg_rest.py 37.83% 11 Missing and 12 partials ⚠️
...c/mountainash_data/core/settings/adapters/mssql.py 47.36% 12 Missing and 8 partials ⚠️
src/mountainash_data/core/connection.py 13.63% 19 Missing ⚠️
...untainash_data/core/settings/adapters/snowflake.py 45.71% 10 Missing and 9 partials ⚠️
...c/mountainash_data/core/settings/adapters/trino.py 36.36% 9 Missing and 5 partials ⚠️
...mountainash_data/core/settings/adapters/pyspark.py 42.10% 4 Missing and 7 partials ⚠️
...ountainash_data/core/settings/adapters/redshift.py 54.16% 4 Missing and 7 partials ⚠️
src/mountainash_data/backends/ibis/connection.py 70.58% 5 Missing and 5 partials ⚠️
...rc/mountainash_data/backends/iceberg/connection.py 0.00% 9 Missing ⚠️
src/mountainash_data/core/settings/profile.py 80.85% 2 Missing and 7 partials ⚠️
... and 10 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #77      +/-   ##
==========================================
+ Coverage   46.91%   54.79%   +7.88%     
==========================================
  Files          53       51       -2     
  Lines        2707     2617      -90     
  Branches      302      288      -14     
==========================================
+ Hits         1270     1434     +164     
+ Misses       1382     1074     -308     
- Partials       55      109      +54     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@discreteds discreteds merged commit 75a89fa into main Apr 18, 2026
7 of 8 checks passed
@discreteds discreteds deleted the release/2026.04.1 branch April 18, 2026 23:50
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.

1 participant