chore: POC for backward compatible checks of models#2273
chore: POC for backward compatible checks of models#2273williambdean wants to merge 10 commits intomainfrom
Conversation
PR SummaryMedium Risk Overview Adds a new Written by Cursor Bugbot for commit 8b58b56. This will update automatically on new commits. Configure here. |
The mamba-org/setup-micromamba@v1 action requires either 'latest' or a version with build number (e.g., '2.3.3-0'). Changed to 'latest' for simplicity and automatic updates.
- Add scripts/backcompat/__init__.py for proper module structure - Enable cache-environment and cache-downloads in setup-micromamba - Remove manual environment creation step (handled by action) This will significantly speed up CI by caching the conda environment across all 7 matrix jobs. Environment is only rebuilt when environment.yml changes.
Add concurrency control to automatically cancel outdated workflow runs when a new commit is pushed to the same PR. This prevents wasting CI resources on superseded commits. Concurrency group uses: - workflow name (Backcompat Check) - PR number (for pull requests) - ref (for direct pushes to branches)
The scripts/__init__.py file only exists on the backwards-compat branch, not on origin/main yet. When CI checks out main to /tmp/repo-main to capture baselines, the import fails. Solution: Copy the __init__.py files from the current branch into the main worktree before running capture. These are just package markers with no logic, so this is safe. Once this PR merges to main, future PRs won't need this workaround.
The entire scripts/backcompat/ directory doesn't exist on origin/main. We need to: 1. Create the directory structure (scripts/backcompat/models/) 2. Copy ALL backcompat scripts (not just __init__.py files) This ensures the backcompat code from the current branch can run against the model definitions from main.
PyTensor 2.31+ moved the 'ancestors' function from pytensor.graph.traversal to pytensor.graph.basic. This change: 1. Updates pymc_marketing/pytensor_utils.py with try/except fallback for compatibility with both old and new PyTensor versions 2. Patches main branch's pytensor_utils.py in CI workflow with the same compatibility fix before running backcompat tests This ensures backcompat tests work regardless of PyTensor version.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2273 +/- ##
==========================================
- Coverage 93.05% 93.04% -0.02%
==========================================
Files 78 78
Lines 12228 12231 +3
==========================================
+ Hits 11379 11380 +1
- Misses 849 851 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| build_kwargs = model_def.build_args_fn() | ||
| fit_kwargs = model_def.fit_args_fn() if model_def.fit_args_fn else {} | ||
| fit_data_kwargs = ( | ||
| model_def.fit_data_fn(build_kwargs) if model_def.fit_data_fn else build_kwargs |
There was a problem hiding this comment.
Inconsistent fit_data_fn fallback between capture and compare
Medium Severity
The fit_data_fn fallback differs between capture.py and compare.py. When fit_data_fn is None, capture.py falls back to build_kwargs (e.g., {"data": df}) while compare.py falls back to {}. This affects 6 of 7 active models (all CLV models). The capture step passes unexpected build_kwargs like data=df through to pm.sample(), while the compare step passes nothing — meaning baseline and candidate models are fitted under different conditions.
Additional Locations (1)
|
@copilot Please add tqdm to the conda enviroment so that it will be installed for these backward compatible checks in the CI/CD |
|
@williambdean I've opened a new pull request, #2295, to work on those changes. Once the pull request is ready, I'll request review from you. |
* Initial plan * chore: add tqdm to conda environment for backcompat checks Co-authored-by: williambdean <57733339+williambdean@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: williambdean <57733339+williambdean@users.noreply.github.com>
| fit_kwargs = model_def.fit_args_fn() if model_def.fit_args_fn else {} | ||
| fit_data_kwargs = ( | ||
| model_def.fit_data_fn(build_kwargs) if model_def.fit_data_fn else {} | ||
| ) |
There was a problem hiding this comment.
Inconsistent fit_data_kwargs fallback between capture and compare
Medium Severity
When fit_data_fn is None, capture.py falls back to build_kwargs (e.g., {"data": df}) while compare.py falls back to {}. This affects 6 of 8 models (all CLV models without an explicit fit_data_fn). The capture step passes extra kwargs like data=df through to fit() and ultimately to pm.sample(), but the compare step does not. The two steps are fitting models with different arguments, undermining the validity of the backward-compatibility comparison. It only works silently because mock_sample accepts and ignores unknown **kwargs.
Additional Locations (1)
| git fetch origin main --depth=1 | ||
| git worktree remove -f "${WORKTREE_DIR}" >/dev/null 2>&1 || true | ||
| rm -rf "${WORKTREE_DIR}" | ||
| git worktree add "${WORKTREE_DIR}" origin/main |
There was a problem hiding this comment.
Local script missing worktree script copy unlike CI
Medium Severity
The local script creates the origin/main worktree and immediately runs python -m scripts.backcompat.capture from it, but unlike the CI workflow, it never copies the current branch's backcompat scripts into the worktree. The CI workflow explicitly does cp -r scripts/backcompat/*.py into the main worktree because these scripts don't exist on main yet. The local script will fail with a ModuleNotFoundError before this PR merges, and after merging, it will use potentially stale scripts from main whenever the backcompat harness is modified on a branch — diverging from CI behavior.
Additional Locations (1)
|
What about building a hash of the generated model (more precisely fgraph_from_model), and having that hard-coded in the CI. Then there is no need to try and run in older versions of the library. Want something dumb? |
|
Would you recommend changing this: pymc-marketing/pymc_marketing/model_builder.py Lines 175 to 223 in beb6224 Currently, it doesn't need data or build for an id. |
|
I don't have a good picture tbh. Caching is not a trivial problem and MMM models have so many moving parts that my confidence in it is pretty low. |


Description
The model_version in the ModelBuilder is a bit brittle.
This puts some checks that a PRs changes would be able to be loaded in again.
Current checks might also be brittle as well. Open to suggestions.
Related Issue
Checklist
pre-commit.ci autofixto auto-fix.📚 Documentation preview 📚: https://pymc-marketing--2273.org.readthedocs.build/en/2273/