clusteraudiencekit 7.3.1__tar.gz → 7.4.2__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.
Files changed (106) hide show
  1. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/.github/workflows/ci.yml +4 -4
  2. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/.github/workflows/tests.yml +2 -2
  3. clusteraudiencekit-7.4.2/.github/workflows/wheels.yml +86 -0
  4. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/.gitignore +2 -0
  5. clusteraudiencekit-7.4.2/.graphifyignore +31 -0
  6. clusteraudiencekit-7.4.2/AUDIT.md +64 -0
  7. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/CHANGELOG.md +82 -1
  8. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/Cargo.lock +265 -231
  9. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/Cargo.toml +7 -8
  10. clusteraudiencekit-7.4.2/PKG-INFO +282 -0
  11. clusteraudiencekit-7.4.2/README.md +232 -0
  12. clusteraudiencekit-7.4.2/TECHNICAL_DEBT.md +96 -0
  13. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/benches/benchmarks.rs +2 -1
  14. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/ROADMAP_HONEST.md +221 -4
  15. clusteraudiencekit-7.4.2/docs/bench/kmeans_1m_results.md +48 -0
  16. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/pyproject.toml +8 -2
  17. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/algorithms.rs +3 -3
  18. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/b2b_governance.rs +3 -3
  19. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/clustering.rs +15 -15
  20. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/clv.rs +46 -1
  21. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/drift_detection.rs +68 -1
  22. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/lookalike.rs +85 -2
  23. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/mod.rs +1 -1
  24. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/neural_networks.rs +17 -21
  25. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/pattern_discovery.rs +2 -2
  26. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/price_intelligence.rs +6 -6
  27. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/privacy.rs +86 -6
  28. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/profiling.rs +192 -7
  29. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/quality_metrics.rs +59 -20
  30. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/revenue_intelligence.rs +8 -8
  31. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/segment_intelligence.rs +6 -6
  32. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/sql_export.rs +8 -10
  33. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/streaming.rs +2 -2
  34. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/temporal_analytics.rs +5 -5
  35. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/lib.rs +2 -5
  36. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/python.rs +38 -14
  37. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/utils/conversions.rs +3 -3
  38. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/utils/validation.rs +2 -2
  39. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/tests/test_wired_modules.py +25 -0
  40. clusteraudiencekit-7.4.2/tools/graphify/README.md +63 -0
  41. clusteraudiencekit-7.4.2/tools/graphify/graphify_adapter.py +242 -0
  42. clusteraudiencekit-7.3.1/PKG-INFO +0 -256
  43. clusteraudiencekit-7.3.1/README.md +0 -207
  44. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/.env.example +0 -0
  45. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/.gitattributes +0 -0
  46. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  47. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  48. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/.github/dependabot.yml +0 -0
  49. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/.github/pull_request_template.md +0 -0
  50. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/.pre-commit-config.yaml +0 -0
  51. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/CONTRIBUTING.md +0 -0
  52. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/LICENSE +0 -0
  53. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/Makefile +0 -0
  54. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/SECURITY.md +0 -0
  55. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/clusteraudiencekit/__init__.py +0 -0
  56. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/CODE_OF_CONDUCT.md +0 -0
  57. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/CONTRIBUTORS.md +0 -0
  58. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/SECURITY_AUDIT.md +0 -0
  59. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/SQL_EXPORT.md +0 -0
  60. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/architecture/README.md +0 -0
  61. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/ARCHITECTURE.md.fabricated-ecosystem +0 -0
  62. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/CI_ERRORS.md +0 -0
  63. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/CONTRIBUTING.md.claude-dupe +0 -0
  64. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/PYPI_UPLOAD.md +0 -0
  65. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/README.md +0 -0
  66. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/ROADMAP.md +0 -0
  67. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/SECURITY.md.stale-duplicate +0 -0
  68. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/WORKFLOW_INTEGRATION.md +0 -0
  69. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/api-reference.md +0 -0
  70. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/architecture.md.stale +0 -0
  71. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/comparison.md +0 -0
  72. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/error-catalog.json +0 -0
  73. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/getting-started-simple.md +0 -0
  74. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/performance-comparison.md +0 -0
  75. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/press-release.md +0 -0
  76. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/docs/archive/troubleshooting.md +0 -0
  77. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/examples/basic_segmentation.py +0 -0
  78. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/examples/sql_export_example.py +0 -0
  79. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/examples/streaming_updates.py +0 -0
  80. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/install.sh +0 -0
  81. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/rust-toolchain.toml +0 -0
  82. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/scripts/install-curl.sh +0 -0
  83. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/scripts/install-from-source.sh +0 -0
  84. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/scripts/install-pip.ps1 +0 -0
  85. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/scripts/install-pip.sh +0 -0
  86. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/scripts/test_dashboards_crossplatform.sh +0 -0
  87. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/activation.rs +0 -0
  88. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/activation_orchestrator.rs +0 -0
  89. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/b2b_segmentation.rs +0 -0
  90. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/behavioral.rs +0 -0
  91. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/churn_prediction.rs +0 -0
  92. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/cohorts.rs +0 -0
  93. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/dashboard.rs +0 -0
  94. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/governance.rs +0 -0
  95. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/heuristic_score_estimator.rs +0 -0
  96. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/k_estimation.rs +0 -0
  97. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/lifecycle.rs +0 -0
  98. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/platform_adapters.rs +0 -0
  99. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/plugins.rs +0 -0
  100. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/rfm.rs +0 -0
  101. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/engine/segments.rs +0 -0
  102. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/src/utils/mod.rs +0 -0
  103. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/tests/test_basic.py +0 -0
  104. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/tests/test_clustering.py +0 -0
  105. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/tests/test_performance.py +0 -0
  106. {clusteraudiencekit-7.3.1 → clusteraudiencekit-7.4.2}/tests/test_sql_export.py +0 -0
@@ -11,7 +11,7 @@ jobs:
11
11
  name: Rust Build & Test
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
- - uses: actions/checkout@v4
14
+ - uses: actions/checkout@v7
15
15
 
16
16
  - uses: dtolnay/rust-toolchain@stable
17
17
 
@@ -36,9 +36,9 @@ jobs:
36
36
  matrix:
37
37
  python-version: ["3.10", "3.11", "3.12"]
38
38
  steps:
39
- - uses: actions/checkout@v4
39
+ - uses: actions/checkout@v7
40
40
 
41
- - uses: actions/setup-python@v5
41
+ - uses: actions/setup-python@v7
42
42
  with:
43
43
  python-version: ${{ matrix.python-version }}
44
44
 
@@ -63,7 +63,7 @@ jobs:
63
63
  name: Cargo Security Audit
64
64
  runs-on: ubuntu-latest
65
65
  steps:
66
- - uses: actions/checkout@v4
66
+ - uses: actions/checkout@v7
67
67
 
68
68
  - uses: dtolnay/rust-toolchain@stable
69
69
 
@@ -7,8 +7,8 @@ jobs:
7
7
  matrix:
8
8
  python-version: ["3.10", "3.11", "3.12"]
9
9
  steps:
10
- - uses: actions/checkout@v4
11
- - uses: actions/setup-python@v5
10
+ - uses: actions/checkout@v7
11
+ - uses: actions/setup-python@v7
12
12
  with:
13
13
  python-version: ${{ matrix.python-version }}
14
14
  - name: Install
@@ -0,0 +1,86 @@
1
+ name: Build & Test Wheels
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ['v*']
7
+ pull_request:
8
+ branches: [main]
9
+
10
+ jobs:
11
+ build-wheels:
12
+ name: Build wheels on ${{ matrix.os }}
13
+ runs-on: ${{ matrix.os }}
14
+ strategy:
15
+ matrix:
16
+ include:
17
+ - os: ubuntu-latest
18
+ target: x86_64
19
+ - os: macos-14
20
+ target: aarch64-apple-darwin
21
+ - os: macos-14
22
+ target: x86_64-apple-darwin
23
+ - os: windows-latest
24
+ target: x86_64
25
+
26
+ steps:
27
+ - uses: actions/checkout@v7
28
+
29
+ - name: Set up Python
30
+ uses: actions/setup-python@v7
31
+ with:
32
+ python-version: '3.11'
33
+
34
+ - name: Set up Rust
35
+ if: runner.os != 'macOS'
36
+ uses: dtolnay/rust-toolchain@stable
37
+
38
+ - name: Build wheels (macOS, via maturin-action for cross-compilation)
39
+ if: runner.os == 'macOS'
40
+ uses: PyO3/maturin-action@v1
41
+ with:
42
+ target: ${{ matrix.target }}
43
+ args: --release --out dist
44
+
45
+ - name: Build wheels (Linux/Windows, native)
46
+ if: runner.os != 'macOS'
47
+ run: |
48
+ pip install --upgrade pip
49
+ pip install maturin
50
+ maturin build --release --out dist
51
+
52
+ - name: Test wheel
53
+ # Skip on the cross-compiled Intel-from-ARM leg -- the wheel is
54
+ # built for a different CPU architecture than this runner.
55
+ if: matrix.target != 'x86_64-apple-darwin'
56
+ shell: bash
57
+ run: |
58
+ pip install dist/*.whl
59
+ pip install pytest scikit-learn
60
+ pytest tests/ -q
61
+
62
+ - name: Upload wheel artifact
63
+ uses: actions/upload-artifact@v4
64
+ with:
65
+ name: wheels-${{ matrix.os }}-${{ matrix.target }}
66
+ path: dist/*.whl
67
+
68
+ publish:
69
+ name: Publish to PyPI
70
+ needs: build-wheels
71
+ if: startsWith(github.ref, 'refs/tags/v')
72
+ runs-on: ubuntu-latest
73
+ environment: pypi
74
+ permissions:
75
+ id-token: write
76
+ steps:
77
+ - uses: actions/download-artifact@v4
78
+ with:
79
+ path: dist
80
+ pattern: wheels-*
81
+ merge-multiple: true
82
+
83
+ - name: Publish to PyPI
84
+ uses: pypa/gh-action-pypi-publish@release/v1
85
+ with:
86
+ packages-dir: dist/
@@ -62,3 +62,5 @@ target/
62
62
  *.log
63
63
  temp/
64
64
  tmp/
65
+
66
+ graphify-out/
@@ -0,0 +1,31 @@
1
+ # Graphify ignore file - https://docs.graphify.com/reference/configuration
2
+ # Keep the scan (and therefore the agent's graph) focused on real source.
3
+ .git/
4
+ .github/
5
+ graphify-out/
6
+
7
+ # Build output / artifacts
8
+ target/
9
+ dist/
10
+ build/
11
+ *.egg-info/
12
+ node_modules/
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # Caches
18
+ __pycache__/
19
+ *.pyc
20
+ .pytest_cache/
21
+ .mypy_cache/
22
+ .ruff_cache/
23
+ .tox/
24
+ .nox/
25
+ .coverage
26
+ htmlcov/
27
+
28
+ # Vendored / generated
29
+ *.min.js
30
+ *.min.css
31
+ *.lock
@@ -0,0 +1,64 @@
1
+ # Repository Audit — ClusterAudienceKit
2
+
3
+ ## Health
4
+
5
+ **GREEN.** This repo arrived already in unusually good shape — three prior
6
+ dedicated passes (OSS-standardization, quick-fix, and a "deep code-review"
7
+ pass that found a real zero-actual-privacy differential-privacy bug) had
8
+ already been merged to `origin/main`, 9 commits ahead of this audit's
9
+ starting clone. This pass fast-forwarded onto that work first, then closed
10
+ a real security gap (3 CVEs via a forced pyo3 major-version bump) and
11
+ verified the external-facing marketing claims against the codebase's own
12
+ source of truth.
13
+
14
+ ## Before Audit (this pass's baseline, after fast-forward to `51cffd2`)
15
+
16
+ Open debt: 9
17
+ Critical: 0 · High: 1 · Medium: 7 (6 immediately fixable, 1 deep-transitive) · Low: 2
18
+
19
+ ## After Audit
20
+
21
+ Open debt: 3
22
+ Critical: 0 · High: 0 · Medium: 2 (TD-0006 transitive deps, TD-0007 external description) · Low: 1 (TD-0008 benchmark marker)
23
+
24
+ ## Items Fixed
25
+
26
+ 1. **TD-0001** — 3 real `cargo-audit` CVEs closed: pyo3 buffer-overflow (RUSTSEC-2025-0020), pyo3 missing-`Sync`-bound (RUSTSEC-2026-0177), crossbeam-epoch invalid-pointer-deref (RUSTSEC-2026-0204). Required bumping pyo3 0.22→0.29 and numpy 0.22→0.29.
27
+ 2. **TD-0002** — 2 real compile breaks from the pyo3 bump (`PyModule::new_bound`→`new`, `pyo3::PyObject`→`pyo3::Py<PyAny>`).
28
+ 3. **TD-0003** — 7 pyo3 0.29 `FromPyObject`-on-`Clone` deprecation warnings, resolved individually per-type (not a blanket fix) based on verified actual usage: 6 types opted into `#[pyclass(from_py_object)]` because they're genuinely extracted from Python arguments; 1 type (`PyFeatureDrift`, construct/return-only) opted out with `#[pyclass(skip_from_py_object)]`.
29
+ 4. **TD-0004** — Fixed a real naming bug in the crate's own public API: `ClusterClusterAudienceKitError` → `ClusterAudienceKitError`, mechanically across 18 files and 60+ call sites.
30
+ 5. **TD-0005** — Removed a dead `bincode` dependency (zero actual call sites anywhere in the repo) and its dead error-enum variant, closing an "unmaintained crate" `cargo-audit` warning as a side effect.
31
+
32
+ ## Items Remaining
33
+
34
+ - **TD-0006** (P2) — 2 residual `cargo-audit` *warnings* (not vulnerabilities): `paste` (unmaintained, transitive via `parquet`) and `anyhow` (unsound, transitive via a non-default-target wasm-tooling chain). Neither is a direct dependency; no safe one-line fix exists.
35
+ - **TD-0007** (P2) — The GitHub repo's short description overstates clustering-algorithm count ("6 clustering algorithms" vs. the project's own `info.algorithms` list of `["kmeans", "kprototypes"]`) and makes an unbenchmarked "1M+ customers in <1s" claim. Documented with exact evidence for the subsequent README/positioning pass; not corrected in this pass per the audit's own sequencing rule (fix the software first, document reality after).
36
+ - **TD-0008** (P3) — Unregistered `pytest.mark.benchmark` produces a harmless warning on every test run.
37
+
38
+ ## Future Phase Work
39
+
40
+ Already comprehensively tracked in the repo's own `docs/ROADMAP_HONEST.md` (5 large Rust-only modules awaiting Python bindings, full K-Prototypes categorical support, gradient-boosting integration) — not duplicated here.
41
+
42
+ ## CI Status
43
+
44
+ Both workflows (`ci.yml`, `tests.yml`) pass `actionlint` clean. `ruff check .` re-verified clean and genuinely enforced (a prior pass fixed it from silently discarding findings).
45
+
46
+ ## Test Status
47
+
48
+ Rust: 439/439 passing (re-verified at every step of the pyo3 bump — before, immediately after the compile fixes, and after the final version bump). Python: 227 passed, 2 skipped, re-verified against a freshly `maturin develop`-built extension after all Rust changes, confirming zero behavioral drift from the pyo3/numpy major-version bump.
49
+
50
+ ## Build Status
51
+
52
+ `cargo build --release`, `cargo test --release --no-default-features --lib`, `cargo clippy --workspace --all-targets` (30 warnings, all pre-existing and confirmed unreachable from the Python API — zero new warnings introduced), `cargo fmt --all -- --check`, and `maturin develop --release` all verified clean at the final commit.
53
+
54
+ ## Security Status
55
+
56
+ `cargo audit`: 0 vulnerabilities (down from 3), 2 unmaintained/unsound warnings remaining on transitive-only dependencies (documented, not force-fixable).
57
+
58
+ ## Dependency Status
59
+
60
+ pyo3/numpy bumped to current major versions (0.29) with zero downstream behavioral breakage beyond the 2 expected compile-time API changes. `crossbeam-epoch` patched via `cargo update --precise`. `bincode` removed entirely (was dead weight).
61
+
62
+ ## Final Assessment
63
+
64
+ This repo's own prior audit passes had already done most of the honesty and bug-fixing work; this pass's genuine contribution is closing a real security gap that required a disruptive major-version dependency bump (not a quick pin) across pyo3/numpy, verified with zero behavioral regression across both the Rust and Python test suites, plus fixing two smaller but real bugs (a dead dependency, a public-API naming typo) this project's own prior passes hadn't caught. The one new finding worth flagging loudly: the GitHub repo's external-facing description makes claims ("6 clustering algorithms", "1M+ customers in <1s") that the project's own internal honesty documentation doesn't support — evidence is captured in `TECHNICAL_DEBT.md` TD-0007 for whoever runs the README/positioning pass next. Version bumped to 7.3.2 for this release; PyPI publish intentionally left to the coordinator to handle directly.
@@ -2,7 +2,88 @@
2
2
 
3
3
  All notable changes to ClusterAudienceKit are documented here.
4
4
 
5
- ## [Unreleased]
5
+ ## [7.4.2] - 2026-10-17
6
+
7
+ ### Fixed
8
+ - Audit remediation: security hardening, correctness fixes, and lint/CI gates.
9
+
10
+ ## [7.4.1] - 2026-10-12
11
+
12
+ ### Security
13
+ - **SQL-injection vector through `PyCondition` field names**: the Python
14
+ `PyCondition(field, operator, value)` constructor interpolated `field`
15
+ verbatim into the SQL produced by `Condition::to_sql` (reached via
16
+ `PyBehavioralSegment::export_sql`), with no validation anywhere on that
17
+ path, so e.g. `PyCondition("x; DROP TABLE t; --", ">", 1.0)` emitted the
18
+ payload straight into generated SQL. `field` is now passed through the
19
+ existing `validate_identifier` guard (the same check already enforced in
20
+ `sql_export.rs`), raising `ValueError` for anything that is not a plain
21
+ identifier. New regression test `test_condition_field_rejects_sql_injection`.
22
+ - **`engine::privacy::DifferentialPrivacy::laplace_noise`/`gaussian_noise`
23
+ did not sample any actual randomness**, so `add_laplace_noise`/
24
+ `add_gaussian_noise` (the Python-exposed differential-privacy API)
25
+ provided **zero real privacy protection** despite being documented as a
26
+ real, shipped feature. `laplace_noise` hardcoded `u = 0.5` in place of a
27
+ uniform(0,1) draw, which — because 0.5 sits exactly on the function's
28
+ branch boundary — made the noise term evaluate to exactly `0.0` on every
29
+ call (data returned completely unmodified). `gaussian_noise` hardcoded
30
+ `sigma * 0.5`, a fixed deterministic shift with no randomness. Both now
31
+ draw real randomness via `rand::thread_rng()` (inverse-CDF sampling for
32
+ Laplace; Box-Muller transform for Gaussian). Verified via the real PyO3
33
+ binding: repeated calls with identical arguments now produce different
34
+ output instead of byte-identical/constant output. New regression tests
35
+ `test_laplace_noise_is_actually_random`/
36
+ `test_gaussian_noise_is_actually_random` assert nonzero variance across
37
+ repeated calls; both fail against the pre-fix code. See
38
+ `docs/ROADMAP_HONEST.md`'s "Deep code-review pass (2026-09-27)" for full
39
+ detail.
40
+
41
+ ### Fixed
42
+ - `engine::lookalike::LookalikeGenerator::generate_lookalike`'s percentile
43
+ threshold was computed from an unsorted copy of the similarity scores
44
+ (`let sorted: Vec<f64> = similarities.to_vec();` — no `.sort()` call
45
+ despite the name), so the "top N%" cutoff silently depended on the
46
+ candidate list's input order rather than the actual similarity
47
+ distribution. The same 100 candidates fed in a different order produced
48
+ 10 vs. 91 lookalikes for an identical "top 10%" request. Fixed by
49
+ actually sorting descending before indexing. New regression test
50
+ `test_percentile_filtering_is_order_independent` (fails against the
51
+ pre-fix code with `left: 10, right: 91`).
52
+ - `engine::drift_detection::DriftDetector::detect_feature_drift`'s
53
+ `DriftMethod::ChiSquare` arm was a hardcoded `0.0` (comment claimed "Use
54
+ KS as proxy" but never called anything), so any caller of
55
+ `detect_feature_drift(..., method="chi_square")` — a real,
56
+ user-selectable, documented option (`parse_drift_method` in
57
+ `src/python.rs` accepts `"chi_square"`/`"chi2"`) — silently got
58
+ `drift_score: 0.0`/`severity: "none"` regardless of actual drift: a total
59
+ false negative. Verified via the real PyO3 binding: a 100x-shifted
60
+ distribution scored 1.0/critical under `"ks"` but 0.0/none under
61
+ `"chi_square"` before the fix. Fixed by actually proxying to
62
+ `kolmogorov_smirnov` (matching the pre-existing `KullbackLeibler` ->
63
+ `hellinger_distance` proxy pattern one line above) — same score/severity
64
+ as KS now. New regression test
65
+ `test_chi_square_drift_method_is_not_a_hardcoded_zero` (fails against the
66
+ pre-fix code). The separate, correctly-implemented standalone
67
+ `chi_square()`/`chi_square_drift` (categorical drift) were never affected.
68
+ See `docs/ROADMAP_HONEST.md` for why a real continuous-data chi-square
69
+ statistic is a follow-up, not done in this pass.
70
+ - `engine::profiling::ProfilingEngine::profile_segment` returned three
71
+ hardcoded values — `separation: 0.5`, `health_score: size.min(100)`, and
72
+ `purity: 0.85` — despite its doc comment promising a real
73
+ stability/cohesion/separation health score. `separation` is now computed
74
+ against the complement (all non-member rows) per feature, `health_score` is
75
+ a bounded combination of the real stability/cohesion/separation
76
+ components, and `purity` is the true clustering purity when ground-truth
77
+ `labels` are passed (new optional argument) or a documented label-free
78
+ homogeneity proxy otherwise. Regression tests assert a well-separated
79
+ segment scores >0.9 separation, a full-coverage segment scores exactly
80
+ `0.0`, and the label purity case equals `0.75`.
81
+ - `engine::quality_metrics::StabilityAnalysis::adjusted_rand_index` was not
82
+ the Adjusted Rand Index at all — it returned `(RandIndex * 2.0 - 1.0)`,
83
+ which mis-scores even trivial inputs (e.g. `0.0` instead of `-0.5` for the
84
+ textbook two-pairings-of-four case). Replaced with the standard
85
+ contingency-table ARI; new tests cover the identical (`1.0`), hand-computed
86
+ `-0.5`, and partial-agreement cases.
6
87
 
7
88
  ## [7.3.1] - 2026-09-22
8
89