package terminology // contested.go: the PRE-CALL half of the word «contested» — the question asked of a candidate BEFORE any // money moves, on nothing but what the drafts already produced. // // WHY THE WORD NEEDS A PREDICATE AT ALL. The mechanisms the owner asked for — a reviewer of another model // family «only on contested clusters», a retry, a fallback (D39.254 п.2/п.6, backlog rows 435 and 438) — // all route on «contested», and today that word has no denominator: nobody can say what share of a book's // candidates it selects, so nobody can say what the routing would COST. A predicate with a measured // population is the thing that has to exist first; the router is the pack after. // // ⛔ THE THRESHOLDS ARE INPUTS, NOT DEFAULTS, and there is no default value anywhere in this file. A // number baked into Go would be a decision about a PAIR (how much do this language's drafts normally // disagree) written into the engine every pair shares, and it would be a decision nobody measured. The // caller passes them; today the only caller is the $0 probe that measures the population across a grid of // them (cmd/tmbankprobe). When a paid consumer appears, its thresholds arrive as configuration carrying // the measurement that chose them. // // ⚠ WHAT THIS PREDICATE CAN AND CANNOT SEE. It runs where buildBankCandidates runs — before the classifier // — so the candidate's TYPE is still the miner's heuristic. It therefore answers «contested BY THE DRAFTS» // and never «contested by type». The other half of the word lives after the answer comes back // (pipeline.BankStopRow.Contest). // ContestOpts are the pre-call predicate's inputs. type ContestOpts struct { // MinConventions is how many distinct DECISIONS the drafts must have made for the candidate to be in // contention at all. Conventions, not Spread: two chunks writing «Море истинной ци» and «море истинной // ци» made ONE decision written two ways, and counting that as a contest would send a normalization nit // to a second model. Below 2 the arm is off — every candidate qualifies on this axis. MinConventions int // MaxLeaderShare is the dominance arm: the share of draft chunks behind the BEST-ranked convention, // above which the contest is considered settled by the drafts themselves (0.75 = three quarters of the // chunks already agree). Zero or negative disables the arm, and then MinConventions decides alone. MaxLeaderShare float64 } // Contest is what the predicate saw, not only what it decided: a bare bool cannot be argued with, and the // numbers below are what a threshold is chosen against. type Contest struct { Contested bool Conventions int // LeaderShare is the best-ranked convention's share of the draft chunks, in [0,1]. It is 1 for a single // convention, and 0 when the drafts proposed nothing at all — see Unsupported, which is the case that // must not be read as «the drafts agreed». LeaderShare float64 // Unsupported marks a candidate no draft rendered at all: the role is asked to render it with nothing // to rank. It is NOT a contest — there is no disagreement — and it is carried separately because a // router that treats it as agreement would send the least-evidenced rows to the cheapest path. Unsupported bool } // Contest applies the pre-call predicate to a candidate. func (c Candidate) Contest(o ContestOpts) Contest { out := Contest{Conventions: c.Conventions()} if len(c.Variants) == 0 { out.Unsupported = true return out // no drafts, no contest: nothing disagreed with anything } total, top := 0, 0 for _, v := range c.Variants { total += v.Chunks if v.Chunks > top { top = v.Chunks } } switch { case total > 0: out.LeaderShare = float64(top) / float64(total) default: // Renderings with no chunk count behind them (a channel that carries the rendering but not its // support). Reported as 0 rather than as 1: «nothing is behind the leader» is what happened, and // calling it dominance would silently settle every such contest. out.LeaderShare = 0 } if out.Conventions < o.MinConventions { return out } if o.MaxLeaderShare > 0 && out.LeaderShare > o.MaxLeaderShare { return out // the drafts already agree by a margin the caller called decisive } out.Contested = true return out }