python-math #7: feat(math): group-k-smoother in clojure-legacy engine mode (PR-D smoother) - #2620
Draft
jucor wants to merge 1 commit into
Draft
python-math #7: feat(math): group-k-smoother in clojure-legacy engine mode (PR-D smoother)#2620jucor wants to merge 1 commit into
jucor wants to merge 1 commit into
Conversation
This was referenced Jul 18, 2026
jucor
marked this pull request as draft
July 18, 2026 01:48
This was referenced Jul 18, 2026
This was referenced Jul 18, 2026
Closed
Closed
Closed
Closed
Closed
Closed
Closed
Closed
Closed
This was referenced Jul 25, 2026
Draft
Draft
Draft
python-math #43: docs(delphi): s7 goal state + journal — mode collapse executed, battery 20/20
#2672
Draft
Draft
Draft
5 tasks
This was referenced Jul 28, 2026
Draft
… mode (PR-D smoother) ## What Ports Clojure's `:group-k-smoother` (`conversation.clj:454-478`), which damps K (the number of opinion groups) so it only switches to a new best value after `:group-k-buffer` (= 4, `conversation.clj:154`) consecutive ticks agree. This applies only in `clojure-legacy` engine mode (the setting that reproduces the old Clojure engine's behavior exactly); default `improved` mode keeps the existing `best_k` logic bit-for-bit. ## Changes - New `polismath/pca_kmeans_rep/group_k_smoother.py`: a pure function `group_k_smoother_update(prev_state, silhouettes_by_k, buffer=4) -> (new_state, smoothed_k)`. Implements the exact Clojure rule, INCLUDING: - the HIGHER-k-wins tie-break: Clojure's `apply max-key ... (keys ...)` returns the LAST maximal argument, and array-map keys iterate ascending — so ties go to the higher k. `conversation.py`'s improved `best_k` uses strict `>` (LOWER k wins) and is left untouched. - the #2536 clamp (`conversation.clj:469-478`): a carried `smoothed_k` absent from the current clusterings falls back to `this_k`, so `smoothed_k` is always a valid key and downstream never KeyErrors. - first-tick acceptance of `this_k` (when `smoothed_k` is `None`) — the cold-start invariant that keeps the two modes identical on tick 1. - Only the top-level smoother is ported; Python has no subgroups (`subgroup_clusters` is hardcoded `{}`), so the parallel subgroup smoother (`conversation.clj:520-560`) is intentionally omitted. - `Conversation._compute_clusters`: in legacy mode computes `silhouettes_by_k` from `group_clusterings`, runs the smoother against `prev_group_k_smoother` (threaded via `recompute()`, PR-A), picks `group_clusters = group_clusterings[smoothed_k]`, and stores the new smoother state + per-k clusterings on the conversation object (NOT persisted — `conv_man.clj:52-74`). Improved mode: `selected_k = best_k`, and the new fields stay `{}` (inert). ## Semantic judgment call (integrator, please verify) The degenerate early-return paths in `_compute_clusters` (fewer than 2 in-conversation participants / fewer than 2 base clusters) do NOT touch the smoother state, so a degenerate tick preserves the prior in-memory smoother memory rather than resetting it; the clamp protects the next real tick. ## Testing TDD RED evidence (before implementing `group_k_smoother.py`): `tests/test_group_k_smoother.py` collection error — "ModuleNotFoundError: No module named 'polismath.pca_kmeans_rep.group_k_smoother'". Tests: 12 new — 10 pure-function (buffer counting, reset-on-change, brief alternation, clamp present/absent, first-tick, higher-k tie-break) + 2 pipeline integration (legacy no-flicker-then-switch-after-4 via a silhouette stub over 9 chained `update_votes` ticks: `smoothed_k == [2,2,2,2,2,2,2,3,3]`; improved mode leaves the smoother inert). Full suite 434 passed, 17 skipped, 47 xfailed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> commit-id:d4dbbfa9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Ports Clojure's
:group-k-smoother(conversation.clj:454-478), which damps K (the number of opinion groups) so it only switches to a new best value after:group-k-buffer(= 4,conversation.clj:154) consecutive ticks agree. This applies only inclojure-legacyengine mode (the setting that reproduces the old Clojure engine's behavior exactly); defaultimprovedmode keeps the existingbest_klogic bit-for-bit.Changes
polismath/pca_kmeans_rep/group_k_smoother.py: a pure functiongroup_k_smoother_update(prev_state, silhouettes_by_k, buffer=4) -> (new_state, smoothed_k). Implements the exact Clojure rule, INCLUDING:apply max-key ... (keys ...)returns the LAST maximal argument, and array-map keys iterate ascending — so ties go to the higher k.conversation.py's improvedbest_kuses strict>(LOWER k wins) and is left untouched.conversation.clj:469-478): a carriedsmoothed_kabsent from the current clusterings falls back tothis_k, sosmoothed_kis always a valid key and downstream never KeyErrors.this_k(whensmoothed_kisNone) — the cold-start invariant that keeps the two modes identical on tick 1.subgroup_clustersis hardcoded{}), so the parallel subgroup smoother (conversation.clj:520-560) is intentionally omitted.Conversation._compute_clusters: in legacy mode computessilhouettes_by_kfromgroup_clusterings, runs the smoother againstprev_group_k_smoother(threaded viarecompute(), PR-A), picksgroup_clusters = group_clusterings[smoothed_k], and stores the new smoother state + per-k clusterings on the conversation object (NOT persisted —conv_man.clj:52-74). Improved mode:selected_k = best_k, and the new fields stay{}(inert).Semantic judgment call (integrator, please verify)
The degenerate early-return paths in
_compute_clusters(fewer than 2 in-conversation participants / fewer than 2 base clusters) do NOT touch the smoother state, so a degenerate tick preserves the prior in-memory smoother memory rather than resetting it; the clamp protects the next real tick.Testing
TDD RED evidence (before implementing
group_k_smoother.py):tests/test_group_k_smoother.pycollection error — "ModuleNotFoundError: No module named 'polismath.pca_kmeans_rep.group_k_smoother'".Tests: 12 new — 10 pure-function (buffer counting, reset-on-change, brief alternation, clamp present/absent, first-tick, higher-k tie-break) + 2 pipeline integration (legacy no-flicker-then-switch-after-4 via a silhouette stub over 9 chained
update_votesticks:smoothed_k == [2,2,2,2,2,2,2,3,3]; improved mode leaves the smoother inert). Full suite 434 passed, 17 skipped, 47 xfailed.Co-Authored-By: Claude Fable 5 noreply@anthropic.com
commit-id:d4dbbfa9
Stack: