churnkit 1.2.8a7__tar.gz → 1.2.8a8__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.8a7 → churnkit-1.2.8a8}/PKG-INFO +1 -1
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/accounts_view.py +48 -2
- churnkit-1.2.8a8/apps/databricks_app/src/auth.py +71 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/data.py +166 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/pyproject.toml +1 -1
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/__init__.py +1 -1
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/.gitignore +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/LICENSE +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/README.md +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/archetype_view.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/config.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/customer_profile.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/default_profile.css +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/default_profile.html +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/masthead.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/state.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/template.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/theme.css +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/apps/databricks_app/src/treemap.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/causal_notebooks/c01_publish_definitions.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/causal_notebooks/c02_archetype_derivation.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/causal_notebooks/c03_approval_gate.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/causal_notebooks/c04_batch_inference.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/causal_notebooks/c05_snapshot_and_dashboard.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/constraints/.gitkeep +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/-1_sample_datasets.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/00_start_here.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/01_data_discovery.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/01a_a_temporal_text_deep_dive.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/01a_temporal_deep_dive.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/01b_temporal_quality.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/01c_temporal_patterns.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/01d_event_aggregation.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/02_source_integrity.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/03_dataset_merge.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/04_column_deep_dive.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/04a_text_columns_deep_dive.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/05_relationship_analysis.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/06_feature_opportunities.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/07_modeling_readiness.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/08_baseline_experiments.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/09_business_alignment.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/10_spec_generation.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/11_scoring_validation.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/exploration_notebooks/12_view_documentation.ipynb +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/.claude/settings.local.json +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/README.md +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/build_framework_phase_map.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/data/create_snapshot.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/data/generate_edi_ticketing_dataset.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/data/generate_retail_dataset.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/data/generate_test_data.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/data/migrate_parquet_to_delta.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/data/migrate_to_temporal.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/databricks/build_wheel.sh +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/databricks/capture_runtime.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/databricks/dbr_init.sh +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/databricks/deploy_dev.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/databricks/generate_constraints.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/databricks/notebook_setup.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/experiments/capture_notebook_outputs.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/experiments/cell_profiling.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/experiments/compare_exploration_runs.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/experiments/compare_versions.sh +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/experiments/patch_dataset_config.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/generate_requirements.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/build_causal_notebooks.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/clean_notebook_outputs.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/export_tutorial_html.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/init_project.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/migrate_notebook_cell_ids.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/plotly_image_preprocessor.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/run_exploration.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/sync_notebooks.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/tag_framework_cells.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/tag_markdown_cells.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/notebooks/test_notebooks.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/release.sh +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/seed_playbooks_volume.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/templates/tutorial_html/conf.json +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/templates/tutorial_html/index.html.j2 +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/scripts/update_notebook_paths.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/active_dataset_store.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/analysis_context.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/column_describer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/dataset_fingerprinter.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/entity_timestamp_deriver.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/exploration_manager.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/explorer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/field_availability_audit.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/findings.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/intent_defaults.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/key_resolver.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/layered_recommendations.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/objective_support_communicator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/prediction_objective_detector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/project_context.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/recommendation_builder.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/recommendations.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/run_namespace.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/sampling.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/schema_report.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/service_unit_detector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/session.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/skip_logic.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/snapshot_grid.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/business/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/business/ab_test_designer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/business/fairness_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/business/intervention_matcher.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/business/ratio_features.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/business/report_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/business/risk_profile.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/business/roi_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/calibration_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/cv_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/error_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/exploration_ledger.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/feature_provenance.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/feature_stability.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/leakage_detector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/model_diagnostics_report.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/noise_tester.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/overfitting_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/parity_report.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/diagnostics/segment_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/discovery/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/discovery/config_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/discovery/discovery_flow.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/discovery/type_inferencer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/interpretability/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/interpretability/cohort_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/interpretability/counterfactual.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/interpretability/individual_explainer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/interpretability/pdp_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/interpretability/shap_explainer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/jupyter_save_hook.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/notebook_html_exporter.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/notebook_progress.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/plotly_preprocessor.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/base.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/cleaning/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/cleaning/consistency.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/cleaning/deduplicate.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/cleaning/impute.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/cleaning/outlier.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/datetime/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/datetime/extract.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/encoding/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/encoding/categorical.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/pipeline.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/registry.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/selection/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/selection/drop_column.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/transform/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/transform/power.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/recommendations/transform/scale.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/visualization/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/visualization/attention_scorer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/visualization/chart_builder.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/visualization/column_paginator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/visualization/console.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/visualization/display.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/visualization/number_formatter.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/artifacts/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/artifacts/fit_artifact_registry.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/cli.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/compat/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/compat/bulk_profiling.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/compat/cell_profiling_hooks.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/compat/detection.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/compat/ops.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/compat/pandas_backend.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/compat/remote_path.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/compat/spark_backend.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/compat/timing.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/base.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/components/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/components/deployer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/components/explainer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/components/feature_eng.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/components/ingester.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/components/profiler.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/components/trainer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/components/transformer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/components/validator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/enums.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/orchestrator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/components/registry.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/config/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/config/column_config.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/config/experiments.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/config/pipeline_config.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/config/source_config.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/naming.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/utils/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/utils/leakage.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/utils/severity.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/core/utils/statistics.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/base.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/cell_builder.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/config.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/databricks_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/local_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/project_init.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/runner.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/scoring_replay.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/script_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/base_stage.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/causal_setup_cell.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s01_ingestion.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s02_profiling.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s03_cleaning.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s04_transformation.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s05_feature_engineering.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s06_feature_selection.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s07_model_training.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s08_deployment.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s09_monitoring.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s10_batch_inference.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s11_feature_store.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s_c01_publish_definitions.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s_c02_archetype_derivation.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s_c03_approval_gate.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s_c04_batch_inference.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_generator/stages/s_c05_snapshot_and_dashboard.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_merge/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_merge/cli.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_merge/config_merger.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_merge/config_parser.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_merge/conflict.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_merge/merge_engine.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_merge/merge_report.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_sync/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_sync/cell_id_standardizer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_sync/cell_types.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_sync/cli.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_sync/sync_engine.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/notebook_sync/sync_report.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/orchestration/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/orchestration/code_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/orchestration/context.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/orchestration/data_materializer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/orchestration/databricks_exporter.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/orchestration/doc_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/databricks_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/databricks_renderer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/exploration_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/findings_parser.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/generation_manifest.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/gold_transform_applicator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/llm_docs_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/models.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/override_merge.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/protocols.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/renderer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/pipeline_generator/user_extensions_emitter.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/spec_generator/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/generators/spec_generator/mlflow_pipeline_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/base.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/factory.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/feature_store/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/feature_store/base.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/feature_store/databricks.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/feature_store/feast_adapter.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/feature_store/local.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/mlflow/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/mlflow/base.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/mlflow/databricks.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/mlflow/experiment_tracker.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/mlflow/local.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/storage/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/storage/base.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/storage/databricks.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/adapters/storage/local.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/databricks_init.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/databricks_job_capture.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/feature_store/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/feature_store/definitions.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/feature_store/manager.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/feature_store/registry.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/iteration/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/iteration/context.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/iteration/feedback_collector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/iteration/orchestrator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/iteration/recommendation_tracker.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/iteration/signals.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/llm_context/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/llm_context/context_builder.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/llm_context/prompts.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/requirements_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/streaming/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/streaming/batch_integration.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/streaming/early_warning_model.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/streaming/event_schema.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/streaming/online_store_writer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/streaming/realtime_scorer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/streaming/trigger_engine.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/integrations/streaming/window_aggregator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/api.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/dataset_resolution.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/decorator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/flags.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/harvest.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/logging.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/persistence.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/registry.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/replay.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/summary.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/runtime/validation.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/approval_gate.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/clusterer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/column_descriptions_writer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/dashboard_profile_override.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/dashboard_views.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/delta_writer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/derivation.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/feature_meta_writer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/archetype_context.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/business_phrase.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/discovery.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/enrichment_pipeline.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/feature_meta_builder.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/llm_prompt.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/markdown_bootstrap.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/predicate_prose.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/prose_backfill.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/quantile_phrasing.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/interpretation/sidecars.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/llm_namer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/playbook_loader.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/playbook_mapper.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/policy_loader.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/population_stats.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/predicate_compiler.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/rule_extractor.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/run_context_writer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/schemas.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/seed_yamls/decision_policy.yaml +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/seed_yamls/response_schemas.yaml +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/seed_yamls/vocabularies.yaml +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/shap_runner.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/snapshot_writer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/sql/dashboard_views.sql +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/causal/top_drivers_writer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/cleaning/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/cleaning/base.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/cleaning/missing_handler.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/cleaning/outlier_handler.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/deployment/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/deployment/batch_scorer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/deployment/champion_challenger.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/deployment/model_registry.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/deployment/retraining_trigger.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/features/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/features/behavioral_features.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/features/customer_segmentation.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/features/feature_definitions.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/features/feature_engineer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/features/feature_manifest.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/features/feature_selector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/features/interaction_features.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/features/temporal_features.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/ingestion/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/ingestion/load_result.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/ingestion/loaders.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/ingestion/source_registry.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/lifecycle/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/lifecycle/config.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/lifecycle/enrich.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/lifecycle/validation.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/baseline_trainer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/cross_validator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/data_splitter.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/feature_profile.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/feature_scaler.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/feature_spec.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/hyperparameter_tuner.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/imbalance_handler.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/mlflow_logger.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/model_comparator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/model_evaluator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/shap_attribution.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/spark_baseline_trainer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/spark_classifier_wrapper.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/spark_feature_scaler.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/threshold_optimizer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/modeling/training_preparator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/monitoring/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/monitoring/alert_manager.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/monitoring/drift_detector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/monitoring/performance_monitor.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/preprocessing/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/preprocessing/transformer_manager.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/categorical_distribution.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/categorical_target_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/column_profiler.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/distribution_analysis.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/drift_detector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/feature_capacity.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/pattern_analysis_config.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/profile_result.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/quality_checks.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/recommendation_filter.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/relationship_detector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/relationship_recommender.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/report_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/scd_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/segment_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/segment_aware_outlier.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/spark_segment_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/spark_temporal_feature_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/spark_temporal_feature_engineer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/spark_time_window_aggregator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/stats_helpers.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/target_level_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/target_validator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/temporal_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/temporal_coverage.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/temporal_feature_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/temporal_feature_engineer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/temporal_pattern_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/temporal_quality_checks.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/temporal_target_analyzer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/text_embedder.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/text_processor.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/text_reducer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/time_series_profiler.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/time_window_aggregator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/type_detector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/profiling/window_recommendation.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scd_history/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scd_history/augment.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scd_history/config.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scd_history/reconstruct.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scd_history/validation.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scoring/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scoring/batch_inference.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scoring/config.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scoring/data_loader.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scoring/exceptions.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/scoring/pipeline_discovery.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/access_guard.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/data_preparer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/point_in_time_join.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/point_in_time_registry.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/scenario_detector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/snapshot_manager.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/spark_temporal_merger.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/synthetic_coordinator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/temporal_merger.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/timestamp_discovery.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/temporal/timestamp_manager.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/transformation/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/transformation/binary_handler.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/transformation/categorical_encoder.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/transformation/datetime_transformer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/transformation/numeric_transformer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/transformation/pipeline.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/adversarial_scoring_validator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/business_sense_gate.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/data_quality_gate.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/data_validators.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/feature_quality_gate.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/gates.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/leakage_gate.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/model_validity_gate.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/pipeline_validation_runner.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/quality_scorer.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/rule_generator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/scoring_pipeline_validator.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/stages/validation/timeseries_detector.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/transforms/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/transforms/artifact_store.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/transforms/executor.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/transforms/fitted.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/transforms/ops.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/transforms/spark_ops.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/tests/exploration_notebooks/test_distributed_dtype_safety.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/tests/exploration_notebooks/test_nb10_run_pipeline_ordering.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/tests/scripts/__init__.py +0 -0
- {churnkit-1.2.8a7 → churnkit-1.2.8a8}/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.8a8
|
|
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
|
|
@@ -6,9 +6,10 @@ available — click a header to resort.
|
|
|
6
6
|
"""
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
+
import pandas as pd
|
|
9
10
|
import streamlit as st
|
|
10
11
|
|
|
11
|
-
from . import data, state
|
|
12
|
+
from . import auth, data, state
|
|
12
13
|
|
|
13
14
|
_TIER_GLYPH = {"Low": "● ", "Medium": "● ", "High": "● "} # dot prefix, coloured via column_config? Streamlit doesn't style per-row — use unicode dots.
|
|
14
15
|
|
|
@@ -20,6 +21,25 @@ def _tier_label(tier) -> str:
|
|
|
20
21
|
return f"{glyph} {tier}"
|
|
21
22
|
|
|
22
23
|
|
|
24
|
+
def _assignment_label(assigned_to, me: str | None) -> str:
|
|
25
|
+
"""Render the ``assigned_to`` cell.
|
|
26
|
+
|
|
27
|
+
``Mine`` is reserved for the current user so a CSM can scan their own
|
|
28
|
+
column at a glance; everyone else surfaces the local-part of their
|
|
29
|
+
email (``jane.doe`` from ``jane.doe@churnkit.com``) for compactness.
|
|
30
|
+
Returns an empty string for unassigned rows so the column visually
|
|
31
|
+
recedes when most rows are blank.
|
|
32
|
+
"""
|
|
33
|
+
if assigned_to is None or (isinstance(assigned_to, float) and pd.isna(assigned_to)):
|
|
34
|
+
return ""
|
|
35
|
+
text = str(assigned_to).strip()
|
|
36
|
+
if not text:
|
|
37
|
+
return ""
|
|
38
|
+
if me and text.lower() == me.lower():
|
|
39
|
+
return "Mine"
|
|
40
|
+
return text.split("@", 1)[0] if "@" in text else text
|
|
41
|
+
|
|
42
|
+
|
|
23
43
|
def render() -> None:
|
|
24
44
|
pb = state.get("selected_playbook")
|
|
25
45
|
ar = state.get("selected_archetype")
|
|
@@ -29,13 +49,34 @@ def render() -> None:
|
|
|
29
49
|
st.info("No accounts in this scope.")
|
|
30
50
|
return
|
|
31
51
|
|
|
52
|
+
# Left-merge the cached assignments frame so the In-scope table can
|
|
53
|
+
# surface "Mine" / owner handle / blank without modifying the upstream
|
|
54
|
+
# ``v_eligible_all_playbooks`` view. Empty assignments DataFrame leaves
|
|
55
|
+
# every row unassigned.
|
|
56
|
+
me = auth.current_user_email()
|
|
57
|
+
try:
|
|
58
|
+
assigns = data.assignments()
|
|
59
|
+
except Exception:
|
|
60
|
+
assigns = pd.DataFrame(columns=["entity_id", "assigned_to"])
|
|
61
|
+
if assigns is None or assigns.empty:
|
|
62
|
+
df = df.assign(assigned_to=None)
|
|
63
|
+
else:
|
|
64
|
+
df = df.merge(
|
|
65
|
+
assigns[["entity_id", "assigned_to"]],
|
|
66
|
+
on="entity_id",
|
|
67
|
+
how="left",
|
|
68
|
+
)
|
|
69
|
+
|
|
32
70
|
display = df[[
|
|
33
71
|
"entity_id", "churn_probability", "expected_loss", "value_at_risk",
|
|
34
72
|
"risk_tier", "archetype_name",
|
|
35
73
|
"policy_rank_among_eligible", "eligible_playbook_count",
|
|
36
|
-
"recommended", "is_holdout",
|
|
74
|
+
"recommended", "is_holdout", "assigned_to",
|
|
37
75
|
]].copy()
|
|
38
76
|
display["risk_tier"] = display["risk_tier"].map(_tier_label)
|
|
77
|
+
display["assigned_to"] = display["assigned_to"].map(
|
|
78
|
+
lambda v: _assignment_label(v, me)
|
|
79
|
+
)
|
|
39
80
|
|
|
40
81
|
display = display.rename(columns={
|
|
41
82
|
"entity_id": "Entity",
|
|
@@ -48,6 +89,7 @@ def render() -> None:
|
|
|
48
89
|
"eligible_playbook_count": "Plays",
|
|
49
90
|
"recommended": "Rec.",
|
|
50
91
|
"is_holdout": "Holdout",
|
|
92
|
+
"assigned_to": "Assigned to",
|
|
51
93
|
})
|
|
52
94
|
|
|
53
95
|
col_config = {
|
|
@@ -61,6 +103,10 @@ def render() -> None:
|
|
|
61
103
|
"Plays": st.column_config.NumberColumn(format="%d", width="small"),
|
|
62
104
|
"Rec.": st.column_config.CheckboxColumn(width="small"),
|
|
63
105
|
"Holdout": st.column_config.CheckboxColumn(width="small"),
|
|
106
|
+
"Assigned to": st.column_config.TextColumn(
|
|
107
|
+
width="small",
|
|
108
|
+
help="CSM who has self-assigned this account. 'Mine' = you.",
|
|
109
|
+
),
|
|
64
110
|
}
|
|
65
111
|
|
|
66
112
|
event = st.dataframe(
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Identity helpers for the Streamlit app.
|
|
2
|
+
|
|
3
|
+
Databricks Apps inject the OAuth-authenticated user's identity into every
|
|
4
|
+
inbound request as ``X-Forwarded-*`` headers. Streamlit exposes those via
|
|
5
|
+
``st.context.headers`` (>=1.37). The notebook-side ``get_current_username``
|
|
6
|
+
in ``customer_retention.analysis.auto_explorer.session`` is NOT reusable
|
|
7
|
+
here -- it reads ``DATABRICKS_USERNAME`` (set only inside notebook tasks)
|
|
8
|
+
and falls back to ``getpass.getuser`` (the App service principal, identical
|
|
9
|
+
for everyone). The App needs request-scoped resolution.
|
|
10
|
+
|
|
11
|
+
Resolution order for ``current_user_email``:
|
|
12
|
+
1. ``X-Forwarded-Email`` request header (production)
|
|
13
|
+
2. ``st.experimental_user.email`` (Streamlit-native fallback)
|
|
14
|
+
3. ``CR_USER`` env var (local dev / tests)
|
|
15
|
+
4. ``None`` (caller decides whether to block)
|
|
16
|
+
|
|
17
|
+
``current_user_handle`` returns the local-part of the email (``jane.doe``
|
|
18
|
+
from ``jane.doe@churnkit.com``) for compact display in tables and button
|
|
19
|
+
labels. Falls back to ``getpass.getuser()`` when no email is resolvable so
|
|
20
|
+
local dev still works without setting any env vars.
|
|
21
|
+
|
|
22
|
+
Streamlit is imported lazily so this module loads cleanly in the test
|
|
23
|
+
venv (which intentionally omits the live-app dependencies).
|
|
24
|
+
"""
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import getpass
|
|
28
|
+
import os
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _from_request_header() -> str | None:
|
|
32
|
+
try:
|
|
33
|
+
import streamlit as st # noqa: PLC0415 - lazy so the module imports without streamlit
|
|
34
|
+
email = st.context.headers.get("X-Forwarded-Email")
|
|
35
|
+
except Exception:
|
|
36
|
+
return None
|
|
37
|
+
return email.strip().lower() if email else None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _from_streamlit_user() -> str | None:
|
|
41
|
+
try:
|
|
42
|
+
import streamlit as st # noqa: PLC0415
|
|
43
|
+
email = getattr(st.experimental_user, "email", None)
|
|
44
|
+
except Exception:
|
|
45
|
+
return None
|
|
46
|
+
return email.strip().lower() if email else None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _from_env() -> str | None:
|
|
50
|
+
raw = os.environ.get("CR_USER")
|
|
51
|
+
return raw.strip().lower() if raw else None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def current_user_email() -> str | None:
|
|
55
|
+
"""Return the logged-in user's email, or ``None`` when not resolvable."""
|
|
56
|
+
return _from_request_header() or _from_streamlit_user() or _from_env()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def current_user_handle() -> str:
|
|
60
|
+
"""Short display handle for the logged-in user.
|
|
61
|
+
|
|
62
|
+
``jane.doe@churnkit.com`` -> ``jane.doe``. Falls back to the OS username
|
|
63
|
+
when no email is available so local dev without ``CR_USER`` still
|
|
64
|
+
renders something deterministic.
|
|
65
|
+
"""
|
|
66
|
+
email = current_user_email()
|
|
67
|
+
if email and "@" in email:
|
|
68
|
+
return email.split("@", 1)[0]
|
|
69
|
+
if email:
|
|
70
|
+
return email
|
|
71
|
+
return getpass.getuser()
|
|
@@ -320,3 +320,169 @@ def run_history() -> pd.DataFrame:
|
|
|
320
320
|
ORDER BY as_of_date DESC
|
|
321
321
|
LIMIT 20
|
|
322
322
|
""")
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
# ---------------------------------------------------------------------------
|
|
326
|
+
# Self-assignment — ``account_assignments`` Delta table
|
|
327
|
+
# ---------------------------------------------------------------------------
|
|
328
|
+
# A CSM clicks "Assign to me" on the L4 customer profile to claim ownership
|
|
329
|
+
# of an account. One row per assigned entity: no row means unassigned. The
|
|
330
|
+
# table is additive (no view modification, no schema migration) and lazy-
|
|
331
|
+
# created on first read or write so the dashboard can drop into existing
|
|
332
|
+
# deployments without an out-of-band DDL step.
|
|
333
|
+
#
|
|
334
|
+
# Race semantics: two CSMs clicking the same unassigned entity within the
|
|
335
|
+
# same second land on a Delta MERGE with ``WHEN NOT MATCHED THEN INSERT``,
|
|
336
|
+
# so exactly one INSERT wins and the loser's next rerun reads the winner's
|
|
337
|
+
# row and renders "Claimed by …". Unassign is restricted to the current
|
|
338
|
+
# owner -- you cannot clear someone else's claim from the UI.
|
|
339
|
+
_ASSIGNMENTS_TABLE = "account_assignments"
|
|
340
|
+
|
|
341
|
+
_TOGGLE_ASSIGNED = "assigned"
|
|
342
|
+
_TOGGLE_UNASSIGNED = "unassigned"
|
|
343
|
+
_TOGGLE_CLAIMED_BY_OTHER = "claimed_by_other"
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _assignments_fqn(cfg: AppConfig) -> str:
|
|
347
|
+
return f"{cfg.fqn_prefix}.{_ASSIGNMENTS_TABLE}"
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def _ensure_assignments_table(cfg: AppConfig) -> None:
|
|
351
|
+
"""Idempotent ``CREATE TABLE IF NOT EXISTS`` for the assignments table.
|
|
352
|
+
|
|
353
|
+
Runs once per process — the Streamlit session keeps a flag so we don't
|
|
354
|
+
fire DDL on every rerun. Safe to call concurrently: ``CREATE TABLE IF
|
|
355
|
+
NOT EXISTS`` is a no-op on a pre-existing table.
|
|
356
|
+
"""
|
|
357
|
+
flag_key = f"_assignments_table_ready::{cfg.fqn_prefix}"
|
|
358
|
+
try:
|
|
359
|
+
if st.session_state.get(flag_key):
|
|
360
|
+
return
|
|
361
|
+
except Exception:
|
|
362
|
+
pass
|
|
363
|
+
with _connect(cfg) as conn:
|
|
364
|
+
cur = conn.cursor()
|
|
365
|
+
try:
|
|
366
|
+
cur.execute(f"""
|
|
367
|
+
CREATE TABLE IF NOT EXISTS {_assignments_fqn(cfg)} (
|
|
368
|
+
entity_id STRING NOT NULL,
|
|
369
|
+
assigned_to STRING NOT NULL,
|
|
370
|
+
assigned_at TIMESTAMP NOT NULL
|
|
371
|
+
) USING DELTA
|
|
372
|
+
""")
|
|
373
|
+
finally:
|
|
374
|
+
cur.close()
|
|
375
|
+
try:
|
|
376
|
+
st.session_state[flag_key] = True
|
|
377
|
+
except Exception:
|
|
378
|
+
pass
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
@st.cache_data(ttl=10, show_spinner=False)
|
|
382
|
+
def assignments() -> pd.DataFrame:
|
|
383
|
+
"""Return all current account assignments.
|
|
384
|
+
|
|
385
|
+
Two columns: ``entity_id`` and ``assigned_to`` (the owner's email).
|
|
386
|
+
Cached for 10s so the In-scope table stays fresh without hammering the
|
|
387
|
+
warehouse on every rerun. Bust the cache via ``data.assignments.clear()``
|
|
388
|
+
after a toggle so the UI reflects the change immediately.
|
|
389
|
+
|
|
390
|
+
Returns an empty DataFrame on the first call before any rows exist —
|
|
391
|
+
callers can safely left-merge against it.
|
|
392
|
+
"""
|
|
393
|
+
cfg = load_config()
|
|
394
|
+
_ensure_assignments_table(cfg)
|
|
395
|
+
return _query(
|
|
396
|
+
cfg,
|
|
397
|
+
f"SELECT entity_id, assigned_to FROM {_assignments_fqn(cfg)}",
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def toggle_assignment(entity_id: str, user_email: str) -> str:
|
|
402
|
+
"""Self-assign or unassign ``entity_id`` for ``user_email``.
|
|
403
|
+
|
|
404
|
+
Returns one of:
|
|
405
|
+
- ``"assigned"`` — row was inserted (entity now owned by user)
|
|
406
|
+
- ``"unassigned"`` — row was deleted (user released their own claim)
|
|
407
|
+
- ``"claimed_by_other"`` — entity is owned by someone else; no DML
|
|
408
|
+
|
|
409
|
+
The MERGE-on-INSERT path protects against the read-then-write race
|
|
410
|
+
where another CSM claimed the entity between our SELECT and our
|
|
411
|
+
INSERT: ``WHEN NOT MATCHED`` collapses to a no-op and we surface
|
|
412
|
+
``claimed_by_other`` on the next rerun via the cached read.
|
|
413
|
+
"""
|
|
414
|
+
if not entity_id or not user_email:
|
|
415
|
+
raise ValueError("entity_id and user_email are required")
|
|
416
|
+
cfg = load_config()
|
|
417
|
+
_ensure_assignments_table(cfg)
|
|
418
|
+
fqn = _assignments_fqn(cfg)
|
|
419
|
+
user = user_email.strip().lower()
|
|
420
|
+
|
|
421
|
+
with _connect(cfg) as conn:
|
|
422
|
+
cur = conn.cursor()
|
|
423
|
+
try:
|
|
424
|
+
cur.execute(
|
|
425
|
+
f"SELECT assigned_to FROM {fqn} WHERE entity_id = :eid LIMIT 1",
|
|
426
|
+
{"eid": entity_id},
|
|
427
|
+
)
|
|
428
|
+
rows = cur.fetchall()
|
|
429
|
+
current = rows[0][0] if rows else None
|
|
430
|
+
|
|
431
|
+
if current is not None and current.strip().lower() != user:
|
|
432
|
+
return _TOGGLE_CLAIMED_BY_OTHER
|
|
433
|
+
|
|
434
|
+
if current is not None:
|
|
435
|
+
cur.execute(
|
|
436
|
+
f"DELETE FROM {fqn} WHERE entity_id = :eid AND assigned_to = :user",
|
|
437
|
+
{"eid": entity_id, "user": user},
|
|
438
|
+
)
|
|
439
|
+
return _TOGGLE_UNASSIGNED
|
|
440
|
+
|
|
441
|
+
# No prior row -- MERGE so a concurrent claim by another CSM
|
|
442
|
+
# cannot produce a duplicate row. The source row carries the
|
|
443
|
+
# candidate (entity, user, now()); the target only inserts when
|
|
444
|
+
# ``entity_id`` is still absent.
|
|
445
|
+
cur.execute(
|
|
446
|
+
f"""
|
|
447
|
+
MERGE INTO {fqn} t
|
|
448
|
+
USING (
|
|
449
|
+
SELECT :eid AS entity_id, :user AS assigned_to, current_timestamp() AS assigned_at
|
|
450
|
+
) s
|
|
451
|
+
ON t.entity_id = s.entity_id
|
|
452
|
+
WHEN NOT MATCHED THEN INSERT (entity_id, assigned_to, assigned_at)
|
|
453
|
+
VALUES (s.entity_id, s.assigned_to, s.assigned_at)
|
|
454
|
+
""",
|
|
455
|
+
{"eid": entity_id, "user": user},
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
cur.execute(
|
|
459
|
+
f"SELECT assigned_to FROM {fqn} WHERE entity_id = :eid LIMIT 1",
|
|
460
|
+
{"eid": entity_id},
|
|
461
|
+
)
|
|
462
|
+
verify = cur.fetchall()
|
|
463
|
+
winner = verify[0][0] if verify else None
|
|
464
|
+
if winner is None:
|
|
465
|
+
return _TOGGLE_CLAIMED_BY_OTHER
|
|
466
|
+
if winner.strip().lower() == user:
|
|
467
|
+
return _TOGGLE_ASSIGNED
|
|
468
|
+
return _TOGGLE_CLAIMED_BY_OTHER
|
|
469
|
+
finally:
|
|
470
|
+
cur.close()
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def assignment_for(entity_id: str) -> str | None:
|
|
474
|
+
"""Return the current owner email for ``entity_id``, or ``None``.
|
|
475
|
+
|
|
476
|
+
Reads through the cached ``assignments()`` frame so the L4 button can
|
|
477
|
+
label itself ("Assign to me" / "Unassign" / "Claimed") without firing
|
|
478
|
+
its own SQL on every rerun.
|
|
479
|
+
"""
|
|
480
|
+
if not entity_id:
|
|
481
|
+
return None
|
|
482
|
+
df = assignments()
|
|
483
|
+
if df is None or df.empty or "entity_id" not in df.columns:
|
|
484
|
+
return None
|
|
485
|
+
hit = df[df["entity_id"].astype(str) == str(entity_id)]
|
|
486
|
+
if hit.empty:
|
|
487
|
+
return None
|
|
488
|
+
return str(hit.iloc[0]["assigned_to"])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "churnkit"
|
|
3
|
-
version = "1.02.
|
|
3
|
+
version = "1.02.8a8"
|
|
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"}
|
|
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.8a7 → churnkit-1.2.8a8}/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.8a7 → churnkit-1.2.8a8}/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
|
|
File without changes
|
{churnkit-1.2.8a7 → churnkit-1.2.8a8}/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.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/explorer.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/findings.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a7 → churnkit-1.2.8a8}/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.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/run_namespace.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/sampling.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/schema_report.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/session.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/skip_logic.py
RENAMED
|
File without changes
|
{churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/auto_explorer/snapshot_grid.py
RENAMED
|
File without changes
|
|
File without changes
|
{churnkit-1.2.8a7 → churnkit-1.2.8a8}/src/customer_retention/analysis/business/ab_test_designer.py
RENAMED
|
File without changes
|