teqo-backup/src/utilities/goalCoverage.ts
Francisco Ignácio Fontoura Solla 5a4a9033ed E8: Conta da cadeira (metas derivadas, potencial por município, cobertura)
- campoParties.ts + committed election-aggregates artifact v2 (campo federal
  votes, federal tally, 2022 majoritarian presidente/governador)
- global campaignGoals (state goal + margin) with staff-only read /
  unrestricted-write access
- municipalityPotential.ts (teto do campo, captura, share intracampo,
  roll-off, proportional state-goal decomposition) and goalCoverage.ts
  (meta vs comprometido semantics locked this session)
- UI: dashboard + list overview 'Cobertura da meta' metric, new list column,
  detail page 'Conta da cadeira' card
- /simplify pass: dropped dead per-request TI-warning computation, O(1)
  potential lookup, deduped near-identical election loaders/tally types/
  percent formatters
2026-07-24 22:54:27 -03:00

136 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { formatElectionNumber } from '@/lib/electionInsights'
import type { MunicipalityPledgeAggregate } from '@/utilities/votePledgeData'
import {
getVoteEstimateForScenario,
VOTE_ESTIMATE_SCENARIOS,
type VoteEstimateScenario,
type VoteEstimateScenarioFields,
} from '@/utilities/voteEstimate'
/**
* E8 "conta da cadeira" — coverage of the goal by auditable pledges.
*
* Semantics locked this session (see the E8 plan's audit finding #2):
* - **meta** = `expectedVotes[cenário] ?? suggestedGoal` — the mesa's own
* expectation when set (`Municipality.expectedVotes`), falling back to the
* goal decomposed from the state goal (`municipalityPotential.ts`).
* - **comprometido** = `aggregate.effectiveByScenario[cenário]` — the pledge
* aggregate ONLY (`estimated[S] ?? declared`, summed over `votePledge`
* rows). It is deliberately **not** `resolveMunicipalityStaffVoteTotal`,
* which lets `expectedVotes` override the pledge sum — using that here
* would report 100% coverage everywhere the projection-sheet import (E4R)
* set an expectation without a single pledge behind it.
*
* Coverage answers "how much of what the mesa expects is backed by an
* auditable commitment", not "did the mesa fill in a number".
*/
export type MunicipalityGoalCoverage = {
goal: number
committed: number
/** committed / goal, or null when goal is zero/negative (avoids a misleading Infinity/NaN). */
coverageRatio: number | null
/** goal − committed; negative means the municipality is over-committed relative to its goal. */
deficit: number
}
/** Read-only zero coverage — never mutate; use for view models outside the staff scope. */
const emptyMunicipalityGoalCoverage: Readonly<MunicipalityGoalCoverage> = {
goal: 0,
committed: 0,
coverageRatio: null,
deficit: 0,
}
/** All three scenarios pointing at the same zero coverage (never mutate). */
export const createEmptyGoalCoverageByScenario = (): Record<
VoteEstimateScenario,
MunicipalityGoalCoverage
> => {
const byScenario = {} as Record<VoteEstimateScenario, MunicipalityGoalCoverage>
for (const scenario of VOTE_ESTIMATE_SCENARIOS) byScenario[scenario] = emptyMunicipalityGoalCoverage
return byScenario
}
/** Coverage for one municipality, one scenario. */
export const computeGoalCoverage = (
expectedVotes: VoteEstimateScenarioFields | null | undefined,
suggestedGoal: number,
pledgeAggregate: MunicipalityPledgeAggregate,
scenario: VoteEstimateScenario,
): MunicipalityGoalCoverage => {
const goal = getVoteEstimateForScenario(expectedVotes, scenario) ?? suggestedGoal
const committed = pledgeAggregate.effectiveByScenario[scenario]
const coverageRatio = goal > 0 ? committed / goal : null
const deficit = goal - committed
return { goal, committed, coverageRatio, deficit }
}
/** Coverage for one municipality, all three scenarios (mirrors `staffVoteTotalByScenario`). */
export const computeGoalCoverageByScenario = (
expectedVotes: VoteEstimateScenarioFields | null | undefined,
suggestedGoal: number,
pledgeAggregate: MunicipalityPledgeAggregate,
): Record<VoteEstimateScenario, MunicipalityGoalCoverage> => {
const coverageByScenario = {} as Record<VoteEstimateScenario, MunicipalityGoalCoverage>
for (const scenario of VOTE_ESTIMATE_SCENARIOS) {
coverageByScenario[scenario] = computeGoalCoverage(
expectedVotes,
suggestedGoal,
pledgeAggregate,
scenario,
)
}
return coverageByScenario
}
/** Sums a list of per-municipality coverages into one aggregate (dashboard/overview total). */
export const aggregateGoalCoverage = (
entries: ReadonlyArray<MunicipalityGoalCoverage>,
): MunicipalityGoalCoverage => {
const goal = entries.reduce((sum, entry) => sum + entry.goal, 0)
const committed = entries.reduce((sum, entry) => sum + entry.committed, 0)
const coverageRatio = goal > 0 ? committed / goal : null
const deficit = goal - committed
return { goal, committed, coverageRatio, deficit }
}
/**
* Generic ratio→percent label, e.g. for `MunicipalityPotential`'s
* `captureRate2022`/`intraFieldShareByYear` diagnostics on the goal-account
* card — shared here so those and `coverageRatio` don't each round/format
* independently.
*/
export const formatRatioAsPercentLabel = (ratio: number | null): string =>
ratio == null ? '—' : `${Math.round(ratio * 100)}%`
/** `coverageRatio` as a rounded percent string, or "—" when the goal is zero/unknown. */
export const formatGoalCoverageRatioLabel = (coverage: MunicipalityGoalCoverage): string =>
formatRatioAsPercentLabel(coverage.coverageRatio)
/** `coverageRatio` clamped to [0, 100] for a `Progress` bar, or `undefined` when unknown. */
export const goalCoverageProgressPercent = (coverage: MunicipalityGoalCoverage): number | undefined =>
coverage.coverageRatio == null ? undefined : Math.min(100, Math.round(coverage.coverageRatio * 100))
/** UI copy for `deficit`: how many votes are missing (or exceeded) relative to the goal. */
export const formatGoalCoverageDeficitLabel = (coverage: MunicipalityGoalCoverage): string => {
if (coverage.goal <= 0) return 'Sem meta definida'
if (coverage.deficit > 0) {
return `Faltam ${formatElectionNumber(coverage.deficit)} votos para a meta`
}
if (coverage.deficit < 0) {
return `${formatElectionNumber(Math.abs(coverage.deficit))} acima da meta`
}
return 'Meta coberta'
}
/**
* `-1.234`/`+300`-style short form of `deficit` for dense table cells — pair
* with `formatGoalCoverageDeficitLabel` as a `title` tooltip (same pattern as
* `StaffMunicipalityVotesDisplay`'s "Nas lideranças" subline).
*/
export const formatGoalCoverageDeficitShortLabel = (coverage: MunicipalityGoalCoverage): string => {
if (coverage.goal <= 0) return '—'
if (coverage.deficit === 0) return '0'
const sign = coverage.deficit > 0 ? '−' : '+'
return `${sign}${formatElectionNumber(Math.abs(coverage.deficit))}`
}