fix(base_settings): restore canonical pydantic assignment semantics#34
Merged
Conversation
Restores canonical pydantic v2 assignment semantics on MountainAshBaseSettings (validate_assignment=True), removes the redundant update_settings_from_dict re-application in __init__, and converts seven meta-field writes to object.__setattr__. Addresses the setattr-bypass-limitation backlog item promoted from mountainash-data. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four-task TDD plan: xfail tests → validate_assignment flip → __init__ refactor → regression guard. Plus a final verify + PR-open task targeting develop per the three-tier flow. Spec: docs/superpowers/specs/2026-04-18-setattr-bypass-fix-design.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codifies the contract to be restored by enabling validate_assignment=True on MountainAshBaseSettings. Covers SecretStr wrapping, StrEnum coercion, AfterValidator transform on direct setattr, update_settings_from_dict, and the DescriptorProfile integration path. Marked xfail(strict=True) — will flip to expected-pass once Change A lands. Spec: docs/superpowers/specs/2026-04-18-setattr-bypass-fix-design.md
Sets model_config["validate_assignment"] = True on MountainAshBaseSettings. Every setattr on an instance (including via update_settings_from_dict, SettingsManager runtime overrides, and apply_runtime_overrides) now runs the field's declared validator pipeline — enum coercion, SecretStr wrapping, AfterValidator transforms. Addresses the setattr-bypass-limitation backlog item. Removes the bypass mechanism that forced PySparkMode.__setattr__ and ConnectionProfile SecretStr defensive code in consumer packages. Flips the canonical-assignment test class out of xfail. Spec: docs/superpowers/specs/2026-04-18-setattr-bypass-fix-design.md
…init__ super().__init__(**valid_attribute_kwargs) already applies kwargs under full pydantic validation. The subsequent update_settings_from_dict(valid_attribute_kwargs) call was overwriting the validated values with raw input — the original source of the setattr-bypass-limitation. Replaces the call plus seven meta-field setattrs with explicit object.__setattr__ writes. Meta-fields are harness bookkeeping, not user config: bypassing validation is intentional and now explicit. SETTINGS_SOURCE_KWARGS is stashed inline here; update_settings_from_dict still stashes it for the SettingsManager and apply_runtime_overrides callsites. Adds a guard test for meta-field bookkeeping. Spec: docs/superpowers/specs/2026-04-18-setattr-bypass-fix-design.md
Explicit assertion that model_config["validate_assignment"] is True on MountainAshBaseSettings. Fails loudly if a future change turns off the canonical assignment contract. Also: - Extends the Task-3 meta-field bookkeeping guard to cover a DescriptorProfile subclass, since descriptor profiles share the same __init__ path. - Clarifies the __init__ comment block: exact spec filename, and explicit note that object.__setattr__ bypasses __pydantic_fields_set__ tracking (intentional, matches pre-Task-2 behaviour — meta-fields are bookkeeping, not model state). Spec: docs/superpowers/specs/2026-04-18-setattr-bypass-fix-design.md
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #34 +/- ##
===========================================
+ Coverage 96.67% 96.90% +0.23%
===========================================
Files 31 31
Lines 841 841
Branches 109 109
===========================================
+ Hits 813 815 +2
+ Misses 16 15 -1
+ Partials 12 11 -1 ☔ View full report in Codecov by Sentry. |
- hatch.toml: set path = ".venv" under [envs.default] so the project env is non-ephemeral and predictable (per repo convention). - pyrightconfig.json: new — pins venvPath/venv to ".venv", includes src + tests, basic type-checking mode, keyed to Python 3.10. - .gitignore: ignore local .hiivmind/ (user-specific workspace symlinks to hiivmind-pulse-gh config outside the repo). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Summary
validate_assignment=TrueonMountainAshBaseSettingsso declared field types (enums,SecretStr,AfterValidatortransforms) are honoured on every post-construction mutation.update_settings_from_dictre-application in__init__that was overwriting validated fields with raw kwargs.__init__to explicitobject.__setattr__to document intentional bypass for harness bookkeeping.Why
Addresses the
setattr-bypass-limitationbacklog item:`mountainash-central/01.principles/mountainash-data/f.backlog/setattr-bypass-limitation.md`
Root cause was `init` applying kwargs twice: once via `super().init(**kwargs)` (with validation) and then again via `update_settings_from_dict` (raw setattr, no validation) — discarding the validated values. Combined with `validate_assignment` being disabled, this forced per-class `setattr` overrides (e.g. `PySparkMode`) and defensive unwrap guards (e.g. `ConnectionProfile._default_driver_kwargs`) across consumer packages.
Commits (bisect-clean)
Test plan
Notes for reviewers
Spec & Design
`docs/superpowers/specs/2026-04-18-setattr-bypass-fix-design.md`
Plan
`docs/superpowers/plans/2026-04-18-setattr-bypass-fix.md`
Follow-up (separate PRs, after this lands and consumers bump)
🤖 Generated with Claude Code