Effort: thorough
The Synthesizer persona today scores debate rounds along the 10 standard
dimensions (scidex/senate/personas/synthesizer.py if present, else
agent.py synthesis path). All 10 reward being right, none rewards
being orthogonal to the existing claim cloud. So the Theorist learns to
restate consensus louder, not to carve out fresh epistemic ground. Add an
explicit orthogonality reward: at the end of each debate round, the
Synthesizer scores the new claim's semantic distance from the centroid of
all prior claims on the same hypothesis; orthogonal claims get a bonus
applied to agent_performance.contribution_score. Over time, agents who
contribute orthogonal angles climb the leaderboard, even when their angle
is initially "less obviously right".
scidex/senate/orthogonality.py::compute_orthogonality(claim_text, prior_claim_texts) -> float in [0,1] — 1 = maximally orthogonal (cosine 0 to centroid), 0 = exact restatement.scidex/core/embeddings.py (or equivalent); centroid = mean embedding of last 30 claims on this hypothesis.synthesis_score_v2 = synthesis_score_v1 + 0.15 * orthogonality_score; capped at original max so total scoring scale unchanged.claim_orthogonality(debate_round_id PK, hypothesis_id, claim_text_hash, orthogonality_score, computed_at).agent_performance.contribution_score updates use synthesis_score_v2; backfill prior 90 days./agent/{id}/debates page shows per-claim orthogonality badge.hyp-A all about "tau hyperphosphorylation"; new claim about "lysosomal autophagy" → orthogonality > 0.6; new claim restating "tau phosphorylation drives toxicity" → orthogonality < 0.2.scidex/senate/personas/ and scidex/senate/judge_arena.py for the current synthesis path.SCIDEX_ORTHO_REWARD_WEIGHT env.scidex/senate/quality_checks.py::is_coherent and zeroing orthogonality if not.scidex/core/embeddings.py (embedding source).scidex/senate/personas/synthesizer.* (Synthesizer scoring point).scidex/senate/quality_checks.py (coherence guard).q-hdiv-anti-mode-collapse-penalty (orthogonality is one penalty input).Files created:
scidex/senate/orthogonality.py — Core module:compute_orthogonality(claim_text, prior_claim_texts) -> float in [0,1]score_debate_claim(hypothesis_id, debate_round_id, claim_text, session_id, agent_id) -> dictquality_checks.is_coherent()backfill_orthogonality(days=90, dry_run=False) -> countssha256(session_id)[0] % 2 == 0 → v2SCIDEX_ORTHO_REWARD_WEIGHT env var (default 0.15)
migrations/20260427_claim_orthogonality.sql — claim_orthogonality table with scoring_version for A/B tracking; applied to PostgreSQLbackfill/backfill_claim_orthogonality.py — CLI entry point for 90-day backfilltests/test_orthogonality.py — 15 tests, all passing (lysosomal > 0.6, tau restatement < 0.2, first claim = 1.0, short = 0.0, gibberish = 0.0)scidex/senate/quality_checks.py — Added is_coherent(text) -> bool (length + char-density + lexical-diversity + real-words checks)api.py — /senate/agent/{agent_id} debate history now fetches avg orthogonality per session from claim_orthogonality and shows a ⊛ score badge (green ≥ 0.7, yellow ≥ 0.4, red otherwise); gracefully hides badge for pre-backfill sessions