profileShare

rasmusjy / roundtable

Read-only snapshot

No repository description.

main default branch 181 files Expires Sep 13, 2026, 9:06 AM
convergence.ts 1,351 bytes
1 /**
2 * The early-stop decision.
3 *
4 * Pure and side-effect free so it can be exhaustively unit-tested. The
5 * orchestrator calls this after each round with the convergence score returned
6 * by the assessor model and the current health of the council.
7 */
8
9 export type StopReason = 'converged' | 'max_rounds' | 'insufficient_models' | 'budget' | 'gavel' | 'continue';
10
11 export interface StopDecision {
12 stop: boolean;
13 reason: StopReason;
14 }
15
16 export interface StopParams {
17 /** Convergence score for the round just completed (0-100). */
18 score: number;
19 /** Threshold at/above which we consider the council converged. */
20 threshold: number;
21 /** 1-based index of the round just completed. */
22 round: number;
23 /** Configured maximum number of critique→revision rounds. */
24 maxRounds: number;
25 /** Number of models still healthy enough to continue. */
26 activeCount: number;
27 }
28
29 export function shouldStop({
30 score,
31 threshold,
32 round,
33 maxRounds,
34 activeCount,
35 }: StopParams): StopDecision {
36 // A debate needs at least two voices; below that there is nothing to debate.
37 if (activeCount < 2) return { stop: true, reason: 'insufficient_models' };
38 if (score >= threshold) return { stop: true, reason: 'converged' };
39 if (round >= maxRounds) return { stop: true, reason: 'max_rounds' };
40 return { stop: false, reason: 'continue' };
41 }
42