Commit f0e6dc3
committed
feat(delphi): D10 — Clojure-parity rep comment selection (PR 8)
Replaces the pre-D10 botched-port `select_rep_comments_df` with a
single-pass reduce that mirrors Clojure `select-rep-comments`
(math/src/polismath/math/repness.clj:212-281).
Sits on top of PR 14a in the spr stack.
## Helpers added (top-level in `repness.py`)
- `passes_by_test(s)` — Clojure `passes-by-test?` (repness.clj:165-170).
OR'd on (rat, pat) and (rdt, pdt) z-sig-90. NO `pa >= 0.5` gate; the
pre-D10 Python gate was an over-restriction with no Clojure analog.
- `beats_best_by_test(s, current_best_z)` — Clojure `beats-best-by-test?`
(repness.clj:133-139). Strict `>` on `max(rat, rdt)`.
- `beats_best_agr(s, current_best)` — Clojure `beats-best-agr?`
(repness.clj:142-162). Four-branch agree-priority logic:
1. na == 0 AND nd == 0 → reject.
2. current_best AND current_best.ra > 1.0 → compare 4-way signed product
`ra * rat * pa * pat`.
3. current_best (else, ra <= 1.0) → compare `pa * pat` only.
4. No current_best → accept if `z90(pat)` OR `(ra > 1.0 AND pa > 0.5)`.
`current_best` stores the RAW row (Clojure repness.clj:250) so the
ra/rat/pa/pat surface stays available across iterations.
- `_finalize_row_for_output(row, *, is_best_agree=False)` — Clojure
`finalize-cmt-stats` (repness.clj:173-188) + best-agree flagging
(repness.clj:262-264). Emits `best_agree=True` and `n_agree=na` for the
best-agree slot.
## `select_rep_comments_df` rewrite
Signature now: `(stats_df, mod_out=None) -> List[Dict[str, Any]]`. Drops
the `agree_count` / `disagree_count` kwargs (Clojure has only a cap of 5).
Per-row state `{sufficient, best, best_agree}` updated by the helpers.
Final assembly: dedup best_agree from sufficient → sort by metric
(agree_metric for repful=='agree', disagree_metric for 'disagree')
→ prepend finalized+flagged best_agree → take 5 → agrees-before-disagrees.
The caller in `conv_repness` drops the `_stats_row_to_dict` wrapping step
(the new function returns finalized dicts directly).
## Two pre-D10 bugs fixed alongside the rewrite
- `pa >= 0.5 / pd >= 0.5` over-gate in the passing filter — removed (no
Clojure analog).
- "Fill from other category" + "first row" fallback blocks — deleted. The
`:best` / `:best_agree` mechanism IS the Clojure fallback.
## Tests (18 new in `tests/test_discrepancy_fixes.py`)
- TestD10PassesByTest (4): agree-side, disagree-side, neither, no pa-gate.
- TestD10BeatsBestByTest (3): None-best, max(rat,rdt), strict `>`.
- TestD10BeatsBestAgr (6): one per Clojure branch + boundary.
- TestD10SelectRepCommentsBoundary (5): empty input, single unvoted row
→ best fallback, sufficient-empty-best-agree-only, take-5 cap +
agrees-before-disagrees, **the eviction edge case** (best_agree outside
sufficient evicting 5th-highest-metric).
## Eviction edge case — flagged
`take(5)` runs AFTER prepending best_agree. If `best_agree` was kept by
`beats_best_agr` as a non-significant agree-priority fallback (failed
`passes_by_test`, qualified via Branch 4) AND `:sufficient` already has 5
entries, the prepend pushes total to 6 and `take(5)` evicts the
5th-highest-metric sufficient entry — possibly a strong dissenting view.
Mirrors Clojure exactly for blob parity. `# TODO(parity-eviction)` comment
at the take(5) site in the production code; entry added under
"Pending — needs team discussion" in PLAN.md; pinned by the synthetic
test above.
## Re-xfailed with updated reasons (D14 / D1 upstream divergence)
Six per-shared-(gid, tid) blob-comparison tests were previously xfailed as
"D5/D6/D7/D8/D10: no shared comments to compare". After D10 there ARE
shared comments (overlap ~20% on vw cold_start), but the per-(gid, tid)
stats still mismatch because Python and Clojure place different
participants in the "same" group ID. That's upstream PCA/KMeans
group-membership divergence (D14 / D1), not D10. Updated xfail reasons
point at D14 / D1. D10 itself is verified by the 18 synthetic tests.
Affected: TestD9ZScoreThresholds::test_z_values_match_clojure,
TestD5ProportionTest::test_pat_values_match_clojure_blob,
TestD6TwoPropTest::test_rat_values_match_clojure_blob,
TestD7RepnessMetric::test_repness_metric_matches_clojure_blob,
TestD8FinalizeStats::test_repful_matches_clojure_blob,
TestD10RepCommentSelection::test_rep_comments_match_clojure.
## Suite delta
- Pre (post-14a baseline): 295 passed, 12 skipped, 58 xfailed.
- Post: 313 passed, 12 skipped, 58 xfailed.
- Delta: +18 passed (the 18 new D10 synthetic tests), 0 failed, no new
xfailed.
## Documentation
- `delphi/docs/PLAN_DISCREPANCY_FIXES.md`: PR 14a row marked landed
(#2564), PR 8 (D10) marked in-flight, eviction concern added to
"Pending — needs team discussion".
- `delphi/docs/CLJ-PARITY-FIXES-JOURNAL.md`: "Session: PR 8 — D10 rep
comment selection (2026-06-11)" entry with full scope, suite delta,
and decisions log pointer.
## /goal mode
This PR is part of an autonomous run (`/goal`) targeting D10 + D11 + D12 +
golden snapshots as a stacked PR series. Decisions made autonomously
(key naming, return type, etc.) are documented in
`~/polis/D10_D11_D12_GOLDENS_DECISIONS.md` for batch user review at the
end of the run.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
commit-id:1b681fef1 parent b3c3c4f commit f0e6dc3
4 files changed
Lines changed: 628 additions & 107 deletions
File tree
- delphi
- docs
- polismath/pca_kmeans_rep
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1406 | 1406 | | |
1407 | 1407 | | |
1408 | 1408 | | |
1409 | | - | |
1410 | | - | |
| 1409 | + | |
| 1410 | + | |
| 1411 | + | |
| 1412 | + | |
| 1413 | + | |
| 1414 | + | |
| 1415 | + | |
| 1416 | + | |
| 1417 | + | |
| 1418 | + | |
| 1419 | + | |
| 1420 | + | |
| 1421 | + | |
| 1422 | + | |
| 1423 | + | |
| 1424 | + | |
| 1425 | + | |
| 1426 | + | |
| 1427 | + | |
| 1428 | + | |
| 1429 | + | |
| 1430 | + | |
| 1431 | + | |
| 1432 | + | |
| 1433 | + | |
| 1434 | + | |
| 1435 | + | |
| 1436 | + | |
| 1437 | + | |
| 1438 | + | |
| 1439 | + | |
| 1440 | + | |
| 1441 | + | |
| 1442 | + | |
| 1443 | + | |
| 1444 | + | |
| 1445 | + | |
| 1446 | + | |
| 1447 | + | |
| 1448 | + | |
| 1449 | + | |
| 1450 | + | |
| 1451 | + | |
| 1452 | + | |
| 1453 | + | |
| 1454 | + | |
| 1455 | + | |
| 1456 | + | |
| 1457 | + | |
| 1458 | + | |
| 1459 | + | |
| 1460 | + | |
| 1461 | + | |
| 1462 | + | |
| 1463 | + | |
| 1464 | + | |
| 1465 | + | |
| 1466 | + | |
| 1467 | + | |
| 1468 | + | |
| 1469 | + | |
| 1470 | + | |
| 1471 | + | |
| 1472 | + | |
| 1473 | + | |
| 1474 | + | |
| 1475 | + | |
| 1476 | + | |
| 1477 | + | |
| 1478 | + | |
| 1479 | + | |
| 1480 | + | |
| 1481 | + | |
| 1482 | + | |
| 1483 | + | |
| 1484 | + | |
| 1485 | + | |
| 1486 | + | |
| 1487 | + | |
| 1488 | + | |
| 1489 | + | |
| 1490 | + | |
| 1491 | + | |
| 1492 | + | |
| 1493 | + | |
| 1494 | + | |
| 1495 | + | |
| 1496 | + | |
| 1497 | + | |
| 1498 | + | |
| 1499 | + | |
| 1500 | + | |
| 1501 | + | |
| 1502 | + | |
| 1503 | + | |
| 1504 | + | |
| 1505 | + | |
| 1506 | + | |
| 1507 | + | |
| 1508 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
32 | | - | |
33 | | - | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| |||
916 | 916 | | |
917 | 917 | | |
918 | 918 | | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
| 922 | + | |
| 923 | + | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
0 commit comments