churnkit 1.2.8a2__tar.gz → 1.2.8a3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/PKG-INFO +1 -1
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/10_spec_generation.ipynb +1 -1
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/pyproject.toml +1 -1
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/__init__.py +1 -1
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/findings_parser.py +60 -2
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/.gitignore +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/LICENSE +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/README.md +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/accounts_view.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/archetype_view.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/config.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/customer_profile.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/data.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/default_profile.css +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/default_profile.html +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/masthead.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/state.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/template.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/theme.css +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/apps/databricks_app/src/treemap.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/causal_notebooks/c01_publish_definitions.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/causal_notebooks/c02_archetype_derivation.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/causal_notebooks/c03_approval_gate.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/causal_notebooks/c04_batch_inference.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/causal_notebooks/c05_snapshot_and_dashboard.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/constraints/.gitkeep +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/-1_sample_datasets.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/00_start_here.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/01_data_discovery.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/01a_a_temporal_text_deep_dive.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/01a_temporal_deep_dive.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/01b_temporal_quality.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/01c_temporal_patterns.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/01d_event_aggregation.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/02_source_integrity.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/03_dataset_merge.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/04_column_deep_dive.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/04a_text_columns_deep_dive.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/05_relationship_analysis.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/06_feature_opportunities.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/07_modeling_readiness.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/08_baseline_experiments.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/09_business_alignment.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/11_scoring_validation.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/12_view_documentation.ipynb +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/.claude/settings.local.json +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/README.md +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/build_framework_phase_map.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/data/create_snapshot.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/data/generate_edi_ticketing_dataset.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/data/generate_retail_dataset.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/data/generate_test_data.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/data/migrate_parquet_to_delta.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/data/migrate_to_temporal.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/databricks/build_wheel.sh +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/databricks/capture_runtime.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/databricks/dbr_init.sh +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/databricks/deploy_dev.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/databricks/generate_constraints.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/databricks/notebook_setup.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/experiments/capture_notebook_outputs.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/experiments/cell_profiling.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/experiments/compare_exploration_runs.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/experiments/compare_versions.sh +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/experiments/patch_dataset_config.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/generate_requirements.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/build_causal_notebooks.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/clean_notebook_outputs.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/export_tutorial_html.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/init_project.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/migrate_notebook_cell_ids.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/plotly_image_preprocessor.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/run_exploration.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/sync_notebooks.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/tag_framework_cells.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/tag_markdown_cells.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/notebooks/test_notebooks.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/release.sh +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/seed_playbooks_volume.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/templates/tutorial_html/conf.json +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/templates/tutorial_html/index.html.j2 +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/scripts/update_notebook_paths.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/active_dataset_store.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/analysis_context.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/column_describer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/dataset_fingerprinter.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/entity_timestamp_deriver.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/exploration_manager.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/explorer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/field_availability_audit.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/findings.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/intent_defaults.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/key_resolver.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/layered_recommendations.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/objective_support_communicator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/prediction_objective_detector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/project_context.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/recommendation_builder.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/recommendations.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/run_namespace.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/sampling.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/schema_report.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/service_unit_detector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/session.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/skip_logic.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/snapshot_grid.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/ab_test_designer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/fairness_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/intervention_matcher.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/ratio_features.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/report_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/risk_profile.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/roi_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/calibration_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/cv_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/error_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/exploration_ledger.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/feature_provenance.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/feature_stability.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/leakage_detector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/model_diagnostics_report.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/noise_tester.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/overfitting_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/parity_report.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/segment_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/discovery/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/discovery/config_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/discovery/discovery_flow.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/discovery/type_inferencer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/interpretability/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/interpretability/cohort_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/interpretability/counterfactual.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/interpretability/individual_explainer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/interpretability/pdp_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/interpretability/shap_explainer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/jupyter_save_hook.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/notebook_html_exporter.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/notebook_progress.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/plotly_preprocessor.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/base.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/cleaning/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/cleaning/consistency.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/cleaning/deduplicate.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/cleaning/impute.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/cleaning/outlier.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/datetime/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/datetime/extract.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/encoding/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/encoding/categorical.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/pipeline.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/registry.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/selection/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/selection/drop_column.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/transform/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/transform/power.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/transform/scale.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/visualization/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/visualization/attention_scorer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/visualization/chart_builder.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/visualization/column_paginator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/visualization/console.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/visualization/display.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/visualization/number_formatter.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/artifacts/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/artifacts/fit_artifact_registry.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/cli.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/compat/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/compat/bulk_profiling.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/compat/cell_profiling_hooks.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/compat/detection.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/compat/ops.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/compat/pandas_backend.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/compat/remote_path.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/compat/spark_backend.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/compat/timing.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/base.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/components/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/components/deployer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/components/explainer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/components/feature_eng.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/components/ingester.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/components/profiler.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/components/trainer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/components/transformer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/components/validator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/enums.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/orchestrator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/components/registry.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/config/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/config/column_config.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/config/experiments.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/config/pipeline_config.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/config/source_config.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/naming.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/utils/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/utils/leakage.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/utils/severity.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/core/utils/statistics.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/base.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/cell_builder.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/config.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/databricks_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/local_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/project_init.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/runner.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/scoring_replay.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/script_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/base_stage.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/causal_setup_cell.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s01_ingestion.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s02_profiling.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s03_cleaning.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s04_transformation.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s05_feature_engineering.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s06_feature_selection.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s07_model_training.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s08_deployment.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s09_monitoring.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s10_batch_inference.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s11_feature_store.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s_c01_publish_definitions.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s_c02_archetype_derivation.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s_c03_approval_gate.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s_c04_batch_inference.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_generator/stages/s_c05_snapshot_and_dashboard.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_merge/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_merge/cli.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_merge/config_merger.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_merge/config_parser.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_merge/conflict.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_merge/merge_engine.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_merge/merge_report.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_sync/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_sync/cell_id_standardizer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_sync/cell_types.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_sync/cli.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_sync/sync_engine.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/notebook_sync/sync_report.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/orchestration/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/orchestration/code_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/orchestration/context.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/orchestration/data_materializer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/orchestration/databricks_exporter.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/orchestration/doc_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/databricks_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/databricks_renderer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/exploration_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/generation_manifest.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/gold_transform_applicator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/llm_docs_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/models.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/override_merge.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/protocols.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/renderer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/pipeline_generator/user_extensions_emitter.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/spec_generator/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/generators/spec_generator/mlflow_pipeline_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/base.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/factory.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/feature_store/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/feature_store/base.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/feature_store/databricks.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/feature_store/feast_adapter.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/feature_store/local.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/mlflow/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/mlflow/base.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/mlflow/databricks.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/mlflow/experiment_tracker.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/mlflow/local.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/storage/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/storage/base.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/storage/databricks.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/adapters/storage/local.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/databricks_init.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/databricks_job_capture.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/feature_store/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/feature_store/definitions.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/feature_store/manager.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/feature_store/registry.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/iteration/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/iteration/context.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/iteration/feedback_collector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/iteration/orchestrator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/iteration/recommendation_tracker.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/iteration/signals.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/llm_context/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/llm_context/context_builder.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/llm_context/prompts.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/requirements_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/streaming/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/streaming/batch_integration.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/streaming/early_warning_model.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/streaming/event_schema.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/streaming/online_store_writer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/streaming/realtime_scorer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/streaming/trigger_engine.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/integrations/streaming/window_aggregator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/api.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/dataset_resolution.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/decorator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/flags.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/harvest.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/logging.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/persistence.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/registry.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/replay.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/summary.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/runtime/validation.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/approval_gate.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/clusterer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/column_descriptions_writer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/dashboard_profile_override.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/dashboard_views.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/delta_writer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/derivation.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/feature_meta_writer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/archetype_context.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/business_phrase.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/discovery.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/enrichment_pipeline.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/feature_meta_builder.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/llm_prompt.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/markdown_bootstrap.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/predicate_prose.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/prose_backfill.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/quantile_phrasing.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/interpretation/sidecars.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/llm_namer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/playbook_loader.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/playbook_mapper.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/policy_loader.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/population_stats.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/predicate_compiler.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/rule_extractor.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/run_context_writer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/schemas.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/seed_yamls/decision_policy.yaml +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/seed_yamls/response_schemas.yaml +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/seed_yamls/vocabularies.yaml +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/shap_runner.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/snapshot_writer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/sql/dashboard_views.sql +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/causal/top_drivers_writer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/cleaning/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/cleaning/base.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/cleaning/missing_handler.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/cleaning/outlier_handler.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/deployment/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/deployment/batch_scorer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/deployment/champion_challenger.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/deployment/model_registry.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/deployment/retraining_trigger.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/features/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/features/behavioral_features.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/features/customer_segmentation.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/features/feature_definitions.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/features/feature_engineer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/features/feature_manifest.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/features/feature_selector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/features/interaction_features.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/features/temporal_features.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/ingestion/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/ingestion/load_result.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/ingestion/loaders.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/ingestion/source_registry.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/lifecycle/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/lifecycle/config.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/lifecycle/enrich.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/lifecycle/validation.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/baseline_trainer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/cross_validator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/data_splitter.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/feature_profile.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/feature_scaler.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/feature_spec.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/hyperparameter_tuner.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/imbalance_handler.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/mlflow_logger.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/model_comparator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/model_evaluator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/shap_attribution.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/spark_baseline_trainer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/spark_classifier_wrapper.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/spark_feature_scaler.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/threshold_optimizer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/modeling/training_preparator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/monitoring/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/monitoring/alert_manager.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/monitoring/drift_detector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/monitoring/performance_monitor.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/preprocessing/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/preprocessing/transformer_manager.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/categorical_distribution.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/categorical_target_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/column_profiler.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/distribution_analysis.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/drift_detector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/feature_capacity.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/pattern_analysis_config.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/profile_result.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/quality_checks.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/recommendation_filter.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/relationship_detector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/relationship_recommender.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/report_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/scd_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/segment_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/segment_aware_outlier.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/spark_segment_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/spark_temporal_feature_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/spark_temporal_feature_engineer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/spark_time_window_aggregator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/stats_helpers.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/target_level_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/target_validator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/temporal_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/temporal_coverage.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/temporal_feature_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/temporal_feature_engineer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/temporal_pattern_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/temporal_quality_checks.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/temporal_target_analyzer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/text_embedder.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/text_processor.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/text_reducer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/time_series_profiler.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/time_window_aggregator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/type_detector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/profiling/window_recommendation.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scd_history/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scd_history/augment.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scd_history/config.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scd_history/reconstruct.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scd_history/validation.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scoring/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scoring/batch_inference.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scoring/config.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scoring/data_loader.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scoring/exceptions.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/scoring/pipeline_discovery.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/access_guard.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/data_preparer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/point_in_time_join.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/point_in_time_registry.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/scenario_detector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/snapshot_manager.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/spark_temporal_merger.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/synthetic_coordinator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/temporal_merger.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/timestamp_discovery.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/temporal/timestamp_manager.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/transformation/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/transformation/binary_handler.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/transformation/categorical_encoder.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/transformation/datetime_transformer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/transformation/numeric_transformer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/transformation/pipeline.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/adversarial_scoring_validator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/business_sense_gate.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/data_quality_gate.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/data_validators.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/feature_quality_gate.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/gates.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/leakage_gate.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/model_validity_gate.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/pipeline_validation_runner.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/quality_scorer.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/rule_generator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/scoring_pipeline_validator.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/stages/validation/timeseries_detector.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/transforms/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/transforms/artifact_store.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/transforms/executor.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/transforms/fitted.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/transforms/ops.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/transforms/spark_ops.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/tests/exploration_notebooks/test_distributed_dtype_safety.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/tests/exploration_notebooks/test_nb10_run_pipeline_ordering.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/tests/scripts/__init__.py +0 -0
- {churnkit-1.2.8a2 → churnkit-1.2.8a3}/tests/scripts/test_build_framework_phase_map.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: churnkit
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.8a3
|
|
4
4
|
Summary: Structured ML framework for customer churn prediction -- from exploration notebooks to production pipelines, locally or on Databricks.
|
|
5
5
|
Project-URL: Homepage, https://github.com/aladjov/CR
|
|
6
6
|
Project-URL: Documentation, https://github.com/aladjov/CR/wiki
|
|
@@ -991,7 +991,7 @@
|
|
|
991
991
|
"tags": []
|
|
992
992
|
},
|
|
993
993
|
"outputs": [],
|
|
994
|
-
"source": "# @cr:code name='run_pipeline' id=8b659505\nRUN_PIPELINE = True\n# Resume gate: skip any landing/bronze/silver/gold notebook whose output UC table\n# already exists. Operator-facing knob — flip to False for a forced full re-run\n# (e.g. when findings or generated code changed in a way that invalidates prior\n# tables). Training is never resume-skipped (no UC table to check; MLflow runs\n# are tracked separately).\nRESUME_FROM_EXISTING_TABLES = True\n\nif RUN_PIPELINE and GENERATION_TARGET == GenerationTarget.DATABRICKS:\n import json as _json\n import time as _time\n\n def _resume_table_for(stage, nb_name, catalog, schema):\n \"\"\"Resolve the UC table written by a generated stage notebook.\n\n Conventions established by the Databricks renderer:\n - landing/landing_<src> -> {cat}.{sch}.landing_<src>\n - bronze/bronze_entity_<src> -> {cat}.{sch}.bronze_entity_<src>\n - bronze/bronze_event_<src> -> {cat}.{sch}.bronze_entity_<src>_events (Shape A)\n - bronze/bronze_entity_<src>_aggregated -> same name as notebook\n - silver/silver_featureset_<CN> -> same name as notebook\n - gold/gold_features_<CN> -> same name as notebook\n - training/* -> None (no UC table)\n \"\"\"\n base = f\"{catalog}.{schema}\"\n if stage == \"landing\":\n return f\"{base}.{nb_name}\"\n if stage == \"bronze\":\n if nb_name.startswith(\"bronze_event_\"):\n source = nb_name[len(\"bronze_event_\"):]\n return f\"{base}.bronze_entity_{source}_events\"\n return f\"{base}.{nb_name}\"\n if stage in (\"silver\", \"gold\"):\n return f\"{base}.{nb_name}\"\n return None\n\n print(f\"Databricks pipeline: {output_dir}\\n\")\n if RESUME_FROM_EXISTING_TABLES:\n print(\"[RESUME] table-existence resume enabled — stages with existing UC tables will be skipped\\n\")\n spark.sql(f\"CREATE SCHEMA IF NOT EXISTS {DATABRICKS_CATALOG}.{DATABRICKS_SCHEMA}\")\n _ns_params = {\"experiments_dir\": str(_namespace.root), \"run_id\": _namespace.run_id} if _namespace else {}\n _stages = [\"landing\", \"bronze\", \"silver\", \"gold\", \"training\"]\n _total_start = _time.time()\n _training_results = None\n _silver_results = None\n _skipped_count = 0\n for _stage in _stages:\n _stage_dir = output_dir / _stage\n if not _stage_dir.exists():\n continue\n if _stage == \"bronze\":\n # (retires NB10 patch §2.11): events must run before\n # entities so the aggregator inputs exist when consumers try\n # to read them. Default sorted() puts `bronze_entity_*`\n # before `bronze_event_*` (i < v) and raises\n # [TABLE_OR_VIEW_NOT_FOUND] on the first aggregated bronze.\n _notebooks = sorted(\n (f.stem for f in _stage_dir.iterdir() if f.suffix == \".py\"),\n key=lambda n: (0 if n.startswith(\"bronze_event_\") else 1, n),\n )\n print(f\"[bronze order] {len(_notebooks)} notebooks; events first:\")\n for _n in _notebooks[:6]:\n print(f\" {_n}\")\n if len(_notebooks) > 6:\n print(f\" ... + {len(_notebooks) - 6} more\")\n else:\n _notebooks = sorted(f.stem for f in _stage_dir.iterdir() if f.suffix == \".py\")\n for _nb in _notebooks:\n _path = str(output_dir / _stage / _nb)\n\n if RESUME_FROM_EXISTING_TABLES:\n _expected = _resume_table_for(_stage, _nb, DATABRICKS_CATALOG, DATABRICKS_SCHEMA)\n if _expected and spark.catalog.tableExists(_expected):\n print(f\"[SKIP] {_stage.upper()}/{_nb}: {_expected} already exists\")\n _skipped_count += 1\n continue\n\n _start = _time.time()\n _result = dbutils.notebook.run(_path, 86400, _ns_params)\n _elapsed = _time.time() - _start\n print(f\"[{_stage.upper()}] {_nb}: {_elapsed:.1f}s\")\n # Generated stage notebooks structured-exit on top-level exceptions\n # with {\"status\":\"FAILED\",...}; raise so the pipeline halts at the\n # failed stage instead of cascading opaque downstream errors.\n _parsed = None\n if _result:\n try:\n _parsed = _json.loads(_result)\n except (ValueError, TypeError):\n if _stage in (\"training\", \"silver\"):\n print(f\" result: {_result}\")\n if isinstance(_parsed, dict) and _parsed.get(\"status\") == \"FAILED\":\n raise RuntimeError(\n f\"[{_stage.upper()}] {_nb} failed: \"\n f\"{_parsed.get('error_type', '?')}: {_parsed.get('error_message', '')} \"\n \"(see spawned-notebook output for full traceback)\"\n )\n if isinstance(_parsed, dict) and _stage == \"training\":\n _training_results = _parsed\n elif isinstance(_parsed, dict) and _stage == \"silver\":\n _silver_results = _parsed\n print(f\"\\nTotal: {_time.time() - _total_start:.1f}s ({_skipped_count} stages skipped via resume)\")\n\n _ns = _namespace\n if _ns is not None:\n _bronze_path = _ns.bronze_metadata_path\n if _bronze_path.exists():\n _bm = _json.loads(_bronze_path.read_text())\n print(\"\\n\" + \"=\" * 60)\n print(\"BRONZE SUMMARY\")\n print(\"=\" * 60)\n print(f\"Sources: {_bm.get('total_sources', 0)}\")\n for _src, _info in _bm.get(\"sources\", {}).items():\n if isinstance(_info, dict):\n print(f\" {_src}: {_info.get('rows', '?'):,} rows, {_info.get('columns', '?')} columns\")\n else:\n print(f\" {_src}: {_info}\")\n\n _gold_path = _ns.gold_metadata_path\n if _gold_path.exists():\n _gm = _json.loads(_gold_path.read_text())\n print(\"\\n\" + \"=\" * 60)\n print(\"GOLD SUMMARY\")\n print(\"=\" * 60)\n print(f\"Rows: {_gm.get('rows', '?'):,}, Columns: {_gm.get('columns', '?')}\")\n if \"feature_count\" in _gm:\n print(f\"Features: {_gm['feature_count']}\")\n if \"feature_version\" in _gm:\n print(f\"Version: {_gm['feature_version']}\")\n if \"elapsed_seconds\" in _gm:\n print(f\"Elapsed: {_gm['elapsed_seconds']}s\")\n\n if _silver_results:\n print(\"\\n\" + \"=\" * 60)\n print(\"SILVER RESULTS\")\n print(\"=\" * 60)\n print(f\"Rows: {_silver_results.get('rows', '?'):,}, Columns: {_silver_results.get('columns', '?')}\")\n _es = _silver_results.get(\"elapsed_seconds\", {})\n if _es:\n print(\"\\nStage timings:\")\n for _name in (\"load_bronze\", \"merge_sources\", \"apply_derived\", \"holdout_mask\", \"delta_write\", \"optimize\", \"total\"):\n if _name in _es:\n print(f\" {_name:<18} {_es[_name]:>8.1f}s\")\n _mb = _silver_results.get(\"merge_breakdown\")\n if _mb:\n print(\"\\nMerge breakdown:\")\n print(f\" Spine: {_mb.get('spine_rows', 0):,} rows = {_mb.get('spine_entities', 0):,} entities x {_mb.get('spine_dates', 0)} dates ({_mb.get('spine_stats_seconds', 0):.1f}s)\")\n print(f\" Checkpoints: {_mb.get('checkpoint_count', 0)} ({_mb.get('checkpoint_seconds', 0):.1f}s)\")\n print(f\" Validation: {_mb.get('validation_seconds', 0):.1f}s\")\n print(f\" Merge total: {_mb.get('merge_total_seconds', 0):.1f}s\")\n _spd = _mb.get(\"seconds_per_dataset\", {})\n _cpd = _mb.get(\"columns_per_dataset\", {})\n print(\"\\nPer-source merge timing:\")\n _ranked = sorted(_mb.get(\"datasets_merged\", []), key=lambda n: _spd.get(n, 0), reverse=True)\n for _name in _ranked:\n print(f\" {_name:<40} {_spd.get(_name, 0):>8.1f}s (+{_cpd.get(_name, 0)} cols)\")\n\n if _training_results:\n print(\"\\n\" + \"=\" * 60)\n print(\"TRAINING RESULTS\")\n print(\"=\" * 60)\n if \"gold_data\" in _training_results:\n _gd = _training_results[\"gold_data\"]\n print(f\"\\nGold data: {_gd.get('rows', '?'):,} rows, {_gd.get('columns', '?')} columns\")\n print(f\"Column types: {_gd.get('column_types', {})}\")\n if \"feature_count\" in _training_results:\n print(f\"Features: {_training_results['feature_count']}\")\n if \"split\" in _training_results:\n _sp = _training_results[\"split\"]\n print(f\"\\nSplit: train={_sp.get('train_count', '?'):,}, test={_sp.get('test_count', '?'):,}\")\n print(f\"Cutoff date: {_sp.get('cutoff_date', 'N/A')}\")\n if \"label_distribution\" in _training_results:\n print(f\"Label distribution: {_training_results['label_distribution']}\")\n _fp = _training_results.get(\"feature_profile\", {})\n if _fp:\n print(f\"\\nFeature profile: production={_fp.get('production_features', '?')}, exploration={_fp.get('exploration_features', '?')}\")\n _disc = _fp.get(\"discrepancies\", [])\n if _disc:\n print(f\"WARNING: {len(_disc)} feature discrepancies vs exploration:\")\n for _d in _disc:\n print(f\" {_d}\")\n elif \"exploration_features\" in _fp:\n print(\"Feature profile matches exploration\")\n _excl = _fp.get(\"excluded_details\", {})\n if _excl:\n print(f\"\\nExclusion details ({len(_excl)} columns):\")\n for _col, _reason in sorted(_excl.items()):\n print(f\" {_col}: {_reason}\")\n if \"models\" in _training_results:\n print(\"\\nModel Results:\")\n print(f\"{'Model':<25} {'AUC':>8} {'PR-AUC':>8} {'F1':>8}\")\n print(\"-\" * 53)\n for _name, _metrics in _training_results[\"models\"].items():\n print(f\"{_name:<25} {_metrics.get('roc_auc', 0):.4f} {_metrics.get('pr_auc', 0):.4f} {_metrics.get('f1', 0):.4f}\")\n if \"best_model\" in _training_results:\n print(f\"\\nBest: {_training_results['best_model']} (AUC={_training_results.get('best_roc_auc', 0):.4f})\")\n\nelif RUN_PIPELINE and GENERATION_TARGET == GenerationTarget.LOCAL_FEAST_MLFLOW:\n import subprocess\n import sys\n runner_path = output_dir / \"pipeline_runner.py\"\n if runner_path.exists():\n print(f\"Running: python {runner_path.name}\")\n print(\"Pipeline: Landing -> Bronze -> Silver -> Gold -> Training...\\n\")\n proc = subprocess.Popen(\n [sys.executable, \"-u\", \"pipeline_runner.py\"],\n cwd=str(output_dir.resolve()),\n stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True,\n )\n for line in proc.stdout:\n print(line, end=\"\", flush=True)\n if proc.wait() != 0:\n raise subprocess.CalledProcessError(proc.returncode, \"pipeline_runner.py\")\n else:\n print(\"pipeline_runner.py not found. Generate first by running cells above.\")\n\nelse:\n print(\"To run the complete pipeline:\")\n print(f\"\\n cd {output_dir}\")\n print(\" python pipeline_runner.py\")"
|
|
994
|
+
"source": "# @cr:code name='run_pipeline' id=8b659505\nRUN_PIPELINE = True\n# Resume gate: skip any landing/bronze/silver/gold notebook whose output UC table\n# already exists. Operator-facing knob — flip to False for a forced full re-run\n# (e.g. when findings or generated code changed in a way that invalidates prior\n# tables). Training is never resume-skipped (no UC table to check; MLflow runs\n# are tracked separately).\nRESUME_FROM_EXISTING_TABLES = True\n\ndef _fmt_int(value, default=\"?\"):\n # Stage metadata writers can emit `null` for row counts when the post-write\n # readback is skipped (a wide-table perf knob); `:,` format on None/str\n # raises TypeError. Wrap every `:,`-formatted summary read.\n if isinstance(value, bool) or value is None:\n return default\n if isinstance(value, (int, float)):\n return f\"{value:,}\"\n return default\n\nif RUN_PIPELINE and GENERATION_TARGET == GenerationTarget.DATABRICKS:\n import json as _json\n import time as _time\n\n def _resume_table_for(stage, nb_name, catalog, schema):\n \"\"\"Resolve the UC table written by a generated stage notebook.\n\n Conventions established by the Databricks renderer:\n - landing/landing_<src> -> {cat}.{sch}.landing_<src>\n - bronze/bronze_entity_<src> -> {cat}.{sch}.bronze_entity_<src>\n - bronze/bronze_event_<src> -> {cat}.{sch}.bronze_entity_<src>_events (Shape A)\n - bronze/bronze_entity_<src>_aggregated -> same name as notebook\n - silver/silver_featureset_<CN> -> same name as notebook\n - gold/gold_features_<CN> -> same name as notebook\n - training/* -> None (no UC table)\n \"\"\"\n base = f\"{catalog}.{schema}\"\n if stage == \"landing\":\n return f\"{base}.{nb_name}\"\n if stage == \"bronze\":\n if nb_name.startswith(\"bronze_event_\"):\n source = nb_name[len(\"bronze_event_\"):]\n return f\"{base}.bronze_entity_{source}_events\"\n return f\"{base}.{nb_name}\"\n if stage in (\"silver\", \"gold\"):\n return f\"{base}.{nb_name}\"\n return None\n\n print(f\"Databricks pipeline: {output_dir}\\n\")\n if RESUME_FROM_EXISTING_TABLES:\n print(\"[RESUME] table-existence resume enabled — stages with existing UC tables will be skipped\\n\")\n spark.sql(f\"CREATE SCHEMA IF NOT EXISTS {DATABRICKS_CATALOG}.{DATABRICKS_SCHEMA}\")\n _ns_params = {\"experiments_dir\": str(_namespace.root), \"run_id\": _namespace.run_id} if _namespace else {}\n _stages = [\"landing\", \"bronze\", \"silver\", \"gold\", \"training\"]\n _total_start = _time.time()\n _training_results = None\n _silver_results = None\n _skipped_count = 0\n for _stage in _stages:\n _stage_dir = output_dir / _stage\n if not _stage_dir.exists():\n continue\n if _stage == \"bronze\":\n # (retires NB10 patch §2.11): events must run before\n # entities so the aggregator inputs exist when consumers try\n # to read them. Default sorted() puts `bronze_entity_*`\n # before `bronze_event_*` (i < v) and raises\n # [TABLE_OR_VIEW_NOT_FOUND] on the first aggregated bronze.\n _notebooks = sorted(\n (f.stem for f in _stage_dir.iterdir() if f.suffix == \".py\"),\n key=lambda n: (0 if n.startswith(\"bronze_event_\") else 1, n),\n )\n print(f\"[bronze order] {len(_notebooks)} notebooks; events first:\")\n for _n in _notebooks[:6]:\n print(f\" {_n}\")\n if len(_notebooks) > 6:\n print(f\" ... + {len(_notebooks) - 6} more\")\n else:\n _notebooks = sorted(f.stem for f in _stage_dir.iterdir() if f.suffix == \".py\")\n for _nb in _notebooks:\n _path = str(output_dir / _stage / _nb)\n\n if RESUME_FROM_EXISTING_TABLES:\n _expected = _resume_table_for(_stage, _nb, DATABRICKS_CATALOG, DATABRICKS_SCHEMA)\n if _expected and spark.catalog.tableExists(_expected):\n print(f\"[SKIP] {_stage.upper()}/{_nb}: {_expected} already exists\")\n _skipped_count += 1\n continue\n\n _start = _time.time()\n _result = dbutils.notebook.run(_path, 86400, _ns_params)\n _elapsed = _time.time() - _start\n print(f\"[{_stage.upper()}] {_nb}: {_elapsed:.1f}s\")\n # Generated stage notebooks structured-exit on top-level exceptions\n # with {\"status\":\"FAILED\",...}; raise so the pipeline halts at the\n # failed stage instead of cascading opaque downstream errors.\n _parsed = None\n if _result:\n try:\n _parsed = _json.loads(_result)\n except (ValueError, TypeError):\n if _stage in (\"training\", \"silver\"):\n print(f\" result: {_result}\")\n if isinstance(_parsed, dict) and _parsed.get(\"status\") == \"FAILED\":\n raise RuntimeError(\n f\"[{_stage.upper()}] {_nb} failed: \"\n f\"{_parsed.get('error_type', '?')}: {_parsed.get('error_message', '')} \"\n \"(see spawned-notebook output for full traceback)\"\n )\n if isinstance(_parsed, dict) and _stage == \"training\":\n _training_results = _parsed\n elif isinstance(_parsed, dict) and _stage == \"silver\":\n _silver_results = _parsed\n print(f\"\\nTotal: {_time.time() - _total_start:.1f}s ({_skipped_count} stages skipped via resume)\")\n\n _ns = _namespace\n if _ns is not None:\n _bronze_path = _ns.bronze_metadata_path\n if _bronze_path.exists():\n _bm = _json.loads(_bronze_path.read_text())\n print(\"\\n\" + \"=\" * 60)\n print(\"BRONZE SUMMARY\")\n print(\"=\" * 60)\n print(f\"Sources: {_bm.get('total_sources', 0)}\")\n for _src, _info in _bm.get(\"sources\", {}).items():\n if isinstance(_info, dict):\n print(f\" {_src}: {_fmt_int(_info.get('rows'))} rows, {_info.get('columns', '?')} columns\")\n else:\n print(f\" {_src}: {_info}\")\n\n _gold_path = _ns.gold_metadata_path\n if _gold_path.exists():\n _gm = _json.loads(_gold_path.read_text())\n print(\"\\n\" + \"=\" * 60)\n print(\"GOLD SUMMARY\")\n print(\"=\" * 60)\n print(f\"Rows: {_fmt_int(_gm.get('rows'))}, Columns: {_gm.get('columns', '?')}\")\n if \"feature_count\" in _gm:\n print(f\"Features: {_gm['feature_count']}\")\n if \"feature_version\" in _gm:\n print(f\"Version: {_gm['feature_version']}\")\n if \"elapsed_seconds\" in _gm:\n print(f\"Elapsed: {_gm['elapsed_seconds']}s\")\n\n if _silver_results:\n print(\"\\n\" + \"=\" * 60)\n print(\"SILVER RESULTS\")\n print(\"=\" * 60)\n print(f\"Rows: {_fmt_int(_silver_results.get('rows'))}, Columns: {_silver_results.get('columns', '?')}\")\n _es = _silver_results.get(\"elapsed_seconds\", {})\n if _es:\n print(\"\\nStage timings:\")\n for _name in (\"load_bronze\", \"merge_sources\", \"apply_derived\", \"holdout_mask\", \"delta_write\", \"optimize\", \"total\"):\n if _name in _es:\n print(f\" {_name:<18} {_es[_name]:>8.1f}s\")\n _mb = _silver_results.get(\"merge_breakdown\")\n if _mb:\n print(\"\\nMerge breakdown:\")\n print(f\" Spine: {_fmt_int(_mb.get('spine_rows'), '0')} rows = {_fmt_int(_mb.get('spine_entities'), '0')} entities x {_mb.get('spine_dates', 0)} dates ({_mb.get('spine_stats_seconds', 0):.1f}s)\")\n print(f\" Checkpoints: {_mb.get('checkpoint_count', 0)} ({_mb.get('checkpoint_seconds', 0):.1f}s)\")\n print(f\" Validation: {_mb.get('validation_seconds', 0):.1f}s\")\n print(f\" Merge total: {_mb.get('merge_total_seconds', 0):.1f}s\")\n _spd = _mb.get(\"seconds_per_dataset\", {})\n _cpd = _mb.get(\"columns_per_dataset\", {})\n print(\"\\nPer-source merge timing:\")\n _ranked = sorted(_mb.get(\"datasets_merged\", []), key=lambda n: _spd.get(n, 0), reverse=True)\n for _name in _ranked:\n print(f\" {_name:<40} {_spd.get(_name, 0):>8.1f}s (+{_cpd.get(_name, 0)} cols)\")\n\n if _training_results:\n print(\"\\n\" + \"=\" * 60)\n print(\"TRAINING RESULTS\")\n print(\"=\" * 60)\n if \"gold_data\" in _training_results:\n _gd = _training_results[\"gold_data\"]\n print(f\"\\nGold data: {_fmt_int(_gd.get('rows'))} rows, {_gd.get('columns', '?')} columns\")\n print(f\"Column types: {_gd.get('column_types', {})}\")\n if \"feature_count\" in _training_results:\n print(f\"Features: {_training_results['feature_count']}\")\n if \"split\" in _training_results:\n _sp = _training_results[\"split\"]\n print(f\"\\nSplit: train={_fmt_int(_sp.get('train_count'))}, test={_fmt_int(_sp.get('test_count'))}\")\n print(f\"Cutoff date: {_sp.get('cutoff_date', 'N/A')}\")\n if \"label_distribution\" in _training_results:\n print(f\"Label distribution: {_training_results['label_distribution']}\")\n _fp = _training_results.get(\"feature_profile\", {})\n if _fp:\n print(f\"\\nFeature profile: production={_fp.get('production_features', '?')}, exploration={_fp.get('exploration_features', '?')}\")\n _disc = _fp.get(\"discrepancies\", [])\n if _disc:\n print(f\"WARNING: {len(_disc)} feature discrepancies vs exploration:\")\n for _d in _disc:\n print(f\" {_d}\")\n elif \"exploration_features\" in _fp:\n print(\"Feature profile matches exploration\")\n _excl = _fp.get(\"excluded_details\", {})\n if _excl:\n print(f\"\\nExclusion details ({len(_excl)} columns):\")\n for _col, _reason in sorted(_excl.items()):\n print(f\" {_col}: {_reason}\")\n if \"models\" in _training_results:\n print(\"\\nModel Results:\")\n print(f\"{'Model':<25} {'AUC':>8} {'PR-AUC':>8} {'F1':>8}\")\n print(\"-\" * 53)\n for _name, _metrics in _training_results[\"models\"].items():\n print(f\"{_name:<25} {_metrics.get('roc_auc', 0):.4f} {_metrics.get('pr_auc', 0):.4f} {_metrics.get('f1', 0):.4f}\")\n if \"best_model\" in _training_results:\n print(f\"\\nBest: {_training_results['best_model']} (AUC={_training_results.get('best_roc_auc', 0):.4f})\")\n\nelif RUN_PIPELINE and GENERATION_TARGET == GenerationTarget.LOCAL_FEAST_MLFLOW:\n import subprocess\n import sys\n runner_path = output_dir / \"pipeline_runner.py\"\n if runner_path.exists():\n print(f\"Running: python {runner_path.name}\")\n print(\"Pipeline: Landing -> Bronze -> Silver -> Gold -> Training...\\n\")\n proc = subprocess.Popen(\n [sys.executable, \"-u\", \"pipeline_runner.py\"],\n cwd=str(output_dir.resolve()),\n stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True,\n )\n for line in proc.stdout:\n print(line, end=\"\", flush=True)\n if proc.wait() != 0:\n raise subprocess.CalledProcessError(proc.returncode, \"pipeline_runner.py\")\n else:\n print(\"pipeline_runner.py not found. Generate first by running cells above.\")\n\nelse:\n print(\"To run the complete pipeline:\")\n print(f\"\\n cd {output_dir}\")\n print(\" python pipeline_runner.py\")"
|
|
995
995
|
},
|
|
996
996
|
{
|
|
997
997
|
"cell_type": "markdown",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "churnkit"
|
|
3
|
-
version = "1.02.
|
|
3
|
+
version = "1.02.8a3"
|
|
4
4
|
description = "Structured ML framework for customer churn prediction -- from exploration notebooks to production pipelines, locally or on Databricks."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {text = "Apache-2.0"}
|
|
@@ -522,7 +522,8 @@ class FindingsParser:
|
|
|
522
522
|
|
|
523
523
|
def _index_raw_source_columns(self, discovered_events: Dict[str, ExplorationFindings]) -> None:
|
|
524
524
|
for name, findings in discovered_events.items():
|
|
525
|
-
|
|
525
|
+
cols = set(findings.columns.keys())
|
|
526
|
+
self._raw_source_columns.setdefault(name, set()).update(cols)
|
|
526
527
|
per_col: Dict[str, List[str]] = {}
|
|
527
528
|
for col_name, col_finding in findings.columns.items():
|
|
528
529
|
tm = getattr(col_finding, "type_metrics", None) or {}
|
|
@@ -537,7 +538,15 @@ class FindingsParser:
|
|
|
537
538
|
for c in top_cats
|
|
538
539
|
]
|
|
539
540
|
if per_col:
|
|
540
|
-
|
|
541
|
+
# Merge — don't replace. Two findings files (entity-level and
|
|
542
|
+
# pre-aggregated) can both register columns under the same
|
|
543
|
+
# source name; the second pass otherwise clobbers the first
|
|
544
|
+
# and loses raw event-stream value-counts (e.g. event_type)
|
|
545
|
+
# that only the entity-level file carries.
|
|
546
|
+
bucket = self._value_counts_by_source.setdefault(name, {})
|
|
547
|
+
for col, vals in per_col.items():
|
|
548
|
+
if col not in bucket:
|
|
549
|
+
bucket[col] = vals
|
|
541
550
|
self._augment_value_counts_from_spec()
|
|
542
551
|
|
|
543
552
|
_SPEC_TRAILING_WINDOW_RE = re.compile(r"^(?P<head>.+)_count_(?:\d+[dhw]|all_time)$")
|
|
@@ -1211,6 +1220,7 @@ class FindingsParser:
|
|
|
1211
1220
|
source_findings: Optional[Dict[str, "ExplorationFindings"]] = None,
|
|
1212
1221
|
) -> None:
|
|
1213
1222
|
self._apply_bronze_recommendations(config, registry)
|
|
1223
|
+
self._apply_registry_bronze_aggregations(config, registry)
|
|
1214
1224
|
self._apply_imbalance_recommendations(config, registry)
|
|
1215
1225
|
self._apply_silver_recommendations(config, registry)
|
|
1216
1226
|
zero_inflation_opt_in_prefixes = self._collect_zero_inflation_opt_in_prefixes(
|
|
@@ -1596,6 +1606,43 @@ class FindingsParser:
|
|
|
1596
1606
|
return name
|
|
1597
1607
|
return None
|
|
1598
1608
|
|
|
1609
|
+
def _apply_registry_bronze_aggregations(
|
|
1610
|
+
self, config: PipelineConfig, registry: RecommendationRegistry
|
|
1611
|
+
) -> None:
|
|
1612
|
+
"""Promote ``registry.bronze_aggregations`` onto event_cfg for sources
|
|
1613
|
+
the operator didn't restate in NB10's ``BRONZE_AGGREGATIONS`` dict.
|
|
1614
|
+
|
|
1615
|
+
Without this, a per-source declaration made via
|
|
1616
|
+
``add_bronze_value_counts`` / ``add_bronze_per_grid_date_mode`` during
|
|
1617
|
+
exploration is silently ignored at codegen unless the operator
|
|
1618
|
+
manually echoes it into NB10. Recs that depend on the per-value count
|
|
1619
|
+
shape (e.g. ``subscription_terminate_to_start_ratio_*``) get dropped.
|
|
1620
|
+
Operator overrides win on conflict; only un-overridden sources are
|
|
1621
|
+
filled in here.
|
|
1622
|
+
"""
|
|
1623
|
+
ba = getattr(registry, "bronze_aggregations", None) or {}
|
|
1624
|
+
if not isinstance(ba, dict) or not ba:
|
|
1625
|
+
return
|
|
1626
|
+
if self._bronze_aggregation_overrides is None:
|
|
1627
|
+
self._bronze_aggregation_overrides = {}
|
|
1628
|
+
for src, entry in ba.items():
|
|
1629
|
+
if src in self._bronze_aggregation_overrides:
|
|
1630
|
+
continue
|
|
1631
|
+
if src not in config.bronze_event:
|
|
1632
|
+
continue
|
|
1633
|
+
if not isinstance(entry, dict):
|
|
1634
|
+
continue
|
|
1635
|
+
recognized = {
|
|
1636
|
+
k: v for k, v in entry.items()
|
|
1637
|
+
if k in _RECOGNIZED_BRONZE_OVERRIDE_KEYS
|
|
1638
|
+
}
|
|
1639
|
+
if not recognized:
|
|
1640
|
+
continue
|
|
1641
|
+
self._bronze_aggregation_overrides[src] = recognized
|
|
1642
|
+
self._apply_bronze_aggregation_overrides(
|
|
1643
|
+
config.bronze_event[src], src,
|
|
1644
|
+
)
|
|
1645
|
+
|
|
1599
1646
|
def _apply_bronze_recommendations(self, config: PipelineConfig, registry: RecommendationRegistry) -> None:
|
|
1600
1647
|
sources_to_process = dict(registry.sources)
|
|
1601
1648
|
if not sources_to_process and hasattr(registry, "bronze") and registry.bronze is not None:
|
|
@@ -2480,6 +2527,17 @@ class FindingsParser:
|
|
|
2480
2527
|
for src in dd.source_columns:
|
|
2481
2528
|
for suffix in ("_delta_hours", "_hour", "_dow", "_is_weekend"):
|
|
2482
2529
|
columns.add(f"{src}{suffix}")
|
|
2530
|
+
# The runtime aggregator computes datetime-derived features per row
|
|
2531
|
+
# (`compute_temporal_features`) and then runs them through the same
|
|
2532
|
+
# window aggregation as numeric `value_columns`. Mirror that fan-out
|
|
2533
|
+
# so silver_derived recs referencing `<src>_<suffix>_<func>_<window>`
|
|
2534
|
+
# (e.g. `PAYMENT_DATE_is_weekend_max_all_time`) survive parity.
|
|
2535
|
+
if agg and agg.windows and agg.agg_funcs:
|
|
2536
|
+
for src in dd.source_columns:
|
|
2537
|
+
for suffix in ("_delta_hours", "_hour", "_dow", "_is_weekend"):
|
|
2538
|
+
for window in agg.windows:
|
|
2539
|
+
for func in agg.agg_funcs:
|
|
2540
|
+
columns.add(f"{src}{suffix}_{func}_{window}")
|
|
2483
2541
|
for text_cfg in event_cfg.text_features:
|
|
2484
2542
|
if text_cfg.component_columns:
|
|
2485
2543
|
columns |= set(text_cfg.component_columns)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/01a_a_temporal_text_deep_dive.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/exploration_notebooks/04a_text_columns_deep_dive.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/explorer.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/findings.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/key_resolver.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/run_namespace.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/sampling.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/schema_report.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/session.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/skip_logic.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/auto_explorer/snapshot_grid.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/ab_test_designer.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/fairness_analyzer.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/ratio_features.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/report_generator.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/risk_profile.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/business/roi_analyzer.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/cv_analyzer.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/error_analyzer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/noise_tester.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/diagnostics/parity_report.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/discovery/config_generator.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/discovery/discovery_flow.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/discovery/type_inferencer.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/interpretability/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/notebook_html_exporter.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/plotly_preprocessor.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/__init__.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/pipeline.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a2 → churnkit-1.2.8a3}/src/customer_retention/analysis/recommendations/registry.py
RENAMED
|
File without changes
|