fix(auto-install): bind STAMP_PATH/OPT_OUT_PATH defaults at call time (#839) - #841
Conversation
There was a problem hiding this comment.
Sorry @robotrocketscience, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThis PR changes ChangesDeferred default resolution for install paths
🎯 2 (Simple) | ⏱️ ~8 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
[claim:review:bagheera:2026-05-15T03:18:25Z] |
robotrocketscience
left a comment
There was a problem hiding this comment.
Review
Substance LGTM. Branch is out of date relative to current github/main — needs rebase before merge (see Blocker below).
What's right
-
Fix mirrors the existing
settings_pathpattern in the same function (auto_install.py:351).settings_path: Path | None = Noneresolved inside the body viatarget_path = settings_path if settings_path is not None else USER_SETTINGS_PATH. PR #841 extends the same pattern tostamp_path/opt_out_pathwith in-place rebinding (if stamp_path is None: stamp_path = STAMP_PATH). Either shape is correct; the in-place rebind is actually slightly cleaner because the resolved value is used at 4 separate sites downstream (read_stamp,stamp_path.parent.mkdir,lock_path = stamp_path.parent / ...,_do_merge(stamp_path=...)). -
Byte-identical production behaviour. Verified the lone production call site at
auto_install.py:552(auto_install_at_cli_entry → maybe_install_manifest(installed_version=installed_version)) — bothstamp_pathandopt_out_pathare omitted there. Post-fix that path takes theNone-default branch and resolves to module-levelSTAMP_PATH/OPT_OUT_PATH, identical to the pre-fix bound default. -
Regression test correctly exercises the property under test.
test_module_attr_monkeypatch_propagates_to_default_argsmonkeypatchesauto_install.STAMP_PATHto a tmp path, callsmaybe_install_manifest(installed_version=..., settings_path=...)with no explicitstamp_path, then assertsread_stamp(stamp) == "2.2.0"against the tmp file. If a future refactor restores the bound-default, the assertion fails because the merge would have written to the real~/.aelfrice/installed-manifest-version. The test docstring also explicitly names the failure mode, which keeps the why-it-exists trail intact. -
Out-of-scope notes are right. Same-shape audit for
read_stamp/write_stamp/read_opt_outs/add_opt_out/remove_opt_outis correctly deferred — they all have the same def-time-bound pattern but aren't on the load-bearing merge path that writes user state.
Blocker — needs rebase
The CHANGELOG diff against current github/main is wrong:
-## [3.2.0] - 2026-05-15
...
-[Unreleased]: ...compare/v3.2.0...HEAD
-[3.2.0]: ...compare/v3.1.0...v3.2.0
+[Unreleased]: ...compare/v3.0.1...HEAD
The PR removes the [3.2.0] - 2026-05-15 section heading and the corresponding compare-link footnote, plus the [Unreleased] compare-link reverts from v3.2.0...HEAD to v3.0.1...HEAD. That's because PR #841 was opened against a base that predates the v3.2.0 release commit 840a7924 (merged 2026-05-15T03:14:21Z, ~1h ago).
Rebase onto current github/main. After rebase the CHANGELOG entry for #839 lands under [Unreleased] and the [3.2.0] section + footnote stay put. Code/test changes should be conflict-free.
Minor / non-blocking
- The CHANGELOG entry is single-paragraph and tells the why-clearly. Could go a little shorter ("monkeypatching
auto_install.STAMP_PATHis silently ignored because the default arg captures the module attribute at def time; fix uses None defaults + body resolution"), but the current length matches the surrounding entry style onv3.mdand the in-band rationale is useful — not worth churning over.
Verdict
Approve after rebase. CI is fully green on the current head; no concerns there. The substantive change is the right shape and the regression test is direct.
|
[release:review:bagheera:2026-05-15T03:21:12Z] |
|
[claim:review:prince:2026-05-15T03:23:05Z] |
…#839) stamp_path and opt_out_path captured the module-level STAMP_PATH / OPT_OUT_PATH constants at function-definition time, so module-attribute monkeypatches in tests were silently ignored — the merge ran against the user's real ~/.aelfrice/installed-manifest-version and opt-out-hooks.json. Found while writing tests for #834. Defaults are now None; the function body resolves them from the module globals (mirroring the settings_path pattern at the top of the same function). Existing call sites that pass paths explicitly are unaffected.
Direct positive assertion: monkeypatch auto_install.STAMP_PATH to a tmp file, call maybe_install_manifest with no explicit stamp_path, then assert the tmp stamp file was written to the new version. If the bound-default regression returns the assertion fails because the real ~/.aelfrice/ stamp got written instead. Existing test_auto_install_at_cli_entry_runs_when_uv_tool docstring updated to drop the now-stale 'real-merge would leak' rationale.
c74c109 to
b67aec6
Compare
|
Reviewed Rebase resolution (CHANGELOG/v3.md): the v3.2.0 release (
Per-commit content unchanged from the pre-rebase versions; the resolution is mechanical and content-preserving. Fix is correct. Two-arg signature change + four-line body addition. Defaults move from This closes the exact testability foot-gun I called out as out-of-scope in my Verification:
Out of scope (per PR body, agree): auditing Re-adding |
|
[release:review:prince:2026-05-15T03:25:03Z] |
|
merge-train: merged b67aec6 → |
Closes #839.
Bug
maybe_install_manifestinsrc/aelfrice/auto_install.pyboundstamp_pathandopt_out_pathto the module-levelSTAMP_PATH/OPT_OUT_PATHconstants at function-definition time:Tests that
monkeypatch.setattr(auto_install, "STAMP_PATH", tmp_path/...)and then callauto_install_at_cli_entry(...)were silently ignored — the merge ran against the user's real~/.aelfrice/installed-manifest-versionand~/.aelfrice/opt-out-hooks.json. I tripped this myself when writing tests for #834 / PR #836.Fix
Two-line signature change + four-line body addition. Defaults are
None; resolution happens inside the function from the module globals (mirrors the existingsettings_pathpattern at the top of the same function).Existing call sites that pass paths explicitly are unaffected. The
cli.pycall path (auto_install_at_cli_entry → maybe_install_manifest(installed_version=...)) takes theNone-default branch and resolves to the realSTAMP_PATH/OPT_OUT_PATH, byte-identical behaviour for production.Test
test_module_attr_monkeypatch_propagates_to_default_args— monkeypatchesauto_install.STAMP_PATHto a tmp file, callsmaybe_install_manifest(installed_version="2.2.0", settings_path=...)with no explicitstamp_path, asserts the tmp stamp file got the new version. If the bound-default regression ever comes back the assertion fails (because the real~/.aelfrice/installed-manifest-versionwould have been written instead).The pre-existing
test_auto_install_at_cli_entry_runs_when_uv_tooldocstring was tightened — it called out the bound-default leak as the rationale for stubbingmaybe_install_manifest. With this PR the leak is fixed; the stub now stands on test-isolation grounds alone.Full suite: 4276 passed, 62 skipped, 75 xfailed.
Out of scope
read_stamp/write_stamp/read_opt_outs/add_opt_out/remove_opt_out. They all default toSTAMP_PATH/OPT_OUT_PATHat function-def time too. They are not the load-bearing merge path that ends up writing user state during a CLI invocation, and refactoring them risks broader API churn for negligible gain. Worth filing as a separate cleanup if a test-side reason ever surfaces.cli.py:6472to pass paths through explicitly. TheNone-default contract is the cleaner shape; the call site stays exactly as it is today.Tier
rook— single function, two-line signature change + four-line body addition + one test + one CHANGELOG entry. No production behaviour change.Summary by CodeRabbit
Bug Fixes
Tests