mostlyright.weather.earnings.fact_builder
mostlyright.weather.earnings.fact_builder
Section titled “mostlyright.weather.earnings.fact_builder”Earnings fact-row builder + fail-closed Kalshi filter (Phase 27, 27-04).
Assembles schema.earnings_fact.v1-shaped rows from STT mention counts (27-03
mostlyright.weather.earnings.stt.count_mentions()) joined to role-parser
turns (27-04 mostlyright.weather.earnings.role_parser.RoleParser), then
applies the fail-closed Kalshi-count filter (D-27.11).
The two venues resolve the SAME fact rows through different filters
(27-RESEARCH-MARKETS-RULES-STT §2):
- Kalshi counts only occurrences spoken by a transcript-anchored company rep
—
kalshi_counted = validate_kalshi_counted_occurrence(role_source, speaker_role). An un-anchorable occurrence (analyst Q&A, or adiarization_advisoryrole_source) is EXCLUDED from the Kalshi count (recall loss accepted to avoid mis-settlement) but RETAINED in the rows. - Polymarket counts ANY speaker — every row contributes to the Polymarket
tally regardless of
kalshi_counted.
The builder is the ONLY place kalshi_counted is set, and it is ALWAYS
derived from the canonical schema hook — never hand-set — so a settlement can
never trust a stored boolean that the provenance does not support.
Functions
Section titled “Functions”apply_kalshi_filter(rows) | Set kalshi_counted on every row via the fail-closed rule (D-27.11). |
|---|---|
build_fact_rows(stt_counts, turns, …[, …]) | Build schema.earnings_fact.v1 rows — one per (ticker, call_id, term, occurrence). |
closed_candidate_count(rows) | Sum of mention_count over closed-compound candidate rows (D-30). |
kalshi_boolean_settles(rows) | Boolean Kalshi settlement: `sum(mention_count |
polymarket_count(rows) | Polymarket any-speaker AUTO tally over auto-countable compound types. |
polymarket_threshold_met(rows, threshold_n) | Polymarket "say X N+ times" bracket: AUTO count >= threshold_n. |
resolve_polymarket_status(rows, threshold_n) | Fail-loud Polymarket resolution over the compound_type axis (D-30 decision 3). |
resolve_status(rows, *, venue[, threshold_n]) | Return a resolution_status for the venue given the counted rows. |
mostlyright.weather.earnings.fact_builder.apply_kalshi_filter(rows)
Section titled “mostlyright.weather.earnings.fact_builder.apply_kalshi_filter(rows)”Set kalshi_counted on every row via the fail-closed rule (D-27.11).
kalshi_counted = validate_kalshi_counted_occurrence(role_source, speaker_role) — True iff BOTH the role_source and speaker_role are
Kalshi-anchorable. Un-anchorable occurrences (analyst Q&A,
diarization_advisory role_source, unknown speaker) get False but
are RETAINED in the returned rows for the Polymarket any-speaker count.
Returns NEW row dicts (does not mutate the inputs).
mostlyright.weather.earnings.fact_builder.build_fact_rows(stt_counts, turns, market_terms, , ticker, call_id, event_time=None)
Section titled “mostlyright.weather.earnings.fact_builder.build_fact_rows(stt_counts, turns, market_terms, , ticker, call_id, event_time=None)”Build schema.earnings_fact.v1 rows — one per (ticker, call_id, term, occurrence).
stt_counts is a sequence of per-term occurrence records from the STT
counter, each carrying at minimum term (the canonical market term),
matched_surface_form (the actually-spoken string), and a turn_index
linking the occurrence to the turns list (so its speaker role is known).
Optional per-occurrence keys: offset_seconds, segment, confidence.
turns are role-parser Turn records (index-aligned with the
transcript). market_terms is the per-term market spec carrying
counting_mode, threshold_n, window_scope, term_match_rule,
term_accepted_forms (JSON string), term_canonical — used to populate
the venue-rule fields on each row.
Returns the rows with kalshi_counted ALREADY derived via
apply_kalshi_filter() (fail-closed). Every occurrence is retained for
the Polymarket any-speaker count; only kalshi_counted distinguishes the
Kalshi-countable subset.
mostlyright.weather.earnings.fact_builder.closed_candidate_count(rows)
Section titled “mostlyright.weather.earnings.fact_builder.closed_candidate_count(rows)”Sum of mention_count over closed-compound candidate rows (D-30).
These are NOT auto-counted for Polymarket, but they COULD flip an outcome
under Polymarket’s “distinct component” wording — resolve_status()
surfaces them for human review rather than settling resolved_no when they
straddle the threshold.
mostlyright.weather.earnings.fact_builder.kalshi_boolean_settles(rows)
Section titled “mostlyright.weather.earnings.fact_builder.kalshi_boolean_settles(rows)”Boolean Kalshi settlement: sum(mention_count | kalshi_counted) >= 1.
Only the Kalshi-counted (transcript-anchored company-rep) occurrences whose
compound_type is auto-countable on Kalshi
(standalone/open/hyphenated — KALSHI_AUTOCOUNT_COMPOUND_TYPES)
contribute. A closed compound (wildfire for fire) is Kalshi-No — it
NEVER flips a boolean Kalshi market — and an affix_derivation counts for
neither venue. This is in ADDITION to the D-27.11 speaker-scope
kalshi_counted gate (analyst / un-anchorable occurrences already excluded).
mostlyright.weather.earnings.fact_builder.polymarket_count(rows)
Section titled “mostlyright.weather.earnings.fact_builder.polymarket_count(rows)”Polymarket any-speaker AUTO tally over auto-countable compound types.
Every occurrence counts regardless of kalshi_counted — Polymarket’s rule
is speaker-blind (§2.1(4)) — BUT only compound_type in
POLYMARKET_AUTOCOUNT_COMPOUND_TYPES (standalone/open/
hyphenated) auto-counts in v1. A closed compound is a candidate-only
type (surfaced for human review by resolve_status(), NOT auto-counted);
an affix_derivation counts for neither venue (D-30 decision 3/4).
mostlyright.weather.earnings.fact_builder.polymarket_threshold_met(rows, threshold_n)
Section titled “mostlyright.weather.earnings.fact_builder.polymarket_threshold_met(rows, threshold_n)”Polymarket "say X N+ times" bracket: AUTO count >= threshold_n.
Uses the auto-countable polymarket_count() (closed candidates excluded).
A closed-candidate straddle is handled by resolve_status() (fail-loud),
not here.
mostlyright.weather.earnings.fact_builder.resolve_polymarket_status(rows, threshold_n)
Section titled “mostlyright.weather.earnings.fact_builder.resolve_polymarket_status(rows, threshold_n)”Fail-loud Polymarket resolution over the compound_type axis (D-30 decision 3).
auto >= threshold->"resolved_yes"(closed candidates irrelevant).auto < thresholdbutauto + closed >= threshold-> the closed candidates COULD flip the outcome, so return the review status (_POLYMARKET_REVIEW_STATUS=="disputed") — NEVER a silent"resolved_no". A human adjudicates whether the closed compounds count.auto + closed < threshold->"resolved_no"(candidates cannot change the outcome, so no review is needed).
auto is polymarket_count() (standalone/open/hyphenated);
affix_derivation rows count for neither venue and are ignored here.
mostlyright.weather.earnings.fact_builder.resolve_status(rows, , venue, threshold_n=None)
Section titled “mostlyright.weather.earnings.fact_builder.resolve_status(rows, , venue, threshold_n=None)”Return a resolution_status for the venue given the counted rows.
venue is "kalshi" (boolean >=1 on Kalshi-counted, auto-countable
compound-type rows) or "polymarket" (delegates to
resolve_polymarket_status() — fail-loud on closed candidates). Returns
"resolved_yes" / "resolved_no" per RESEARCH-MARKETS §2.1(6), plus
"disputed" for a Polymarket closed-candidate straddle (D-30 decision 3). A
no_qualifying_event (no rows at all) surfaces as "no_qualifying_event".
Kalshi resolution is unchanged except the compound-type restriction (a
closed-only mention still resolves Kalshi-No, which is correct).