mostlyright.weather.earnings
mostlyright.weather.earnings
Section titled “mostlyright.weather.earnings”Earnings-audio Tier-2 ENGINE module (Phase 27, 27-03).
The on-device capture + STT engine for the earnings.live source AND the
exact code “our infra” runs centrally for the default earnings.hosted path
(D-27.18, one SDK / one monorepo). Structurally identical to the weather
[satellite] fetcher: an optional-extra module whose heavy runtime deps
(faster-whisper for STT, av for the transient audio extract) live behind
the EXISTING [earnings] optional extra and are LAZY-imported inside the
capture/STT methods — so importing this module + running the unit tests needs
only the base weather deps.
Three surfaces:
EarningsCalendarPoller (calendar_poller)
: Venue-derived capture trigger (D-27.7). Reads the codegen
earnings-calendar.json seed and emits capture jobs 1-2 days pre-call —
NOT continuous polling of the ~149-series roster (RESEARCH-MARKETS §1.3).
capture package (CaptureAdapter ABC + Q4CaptureAdapter)
: The provider-aware webcast capture fleet. Q4 (widest large-cap coverage)
ships first: drive the PUBLIC guest path then cold ranged-GET the static
static.events.q4inc.com/.../*.mp4 — no auth/DRM/captcha circumvention
(RESEARCH §2). Audio is a TRANSIENT artifact, deleted post-transcription
(D-27.9). The ABC is structured so a live() seam slots in for the
live-during-call IVS path in 27-09.
SttTranscriber (stt)
: faster-whisper (CTranslate2) transcriber with per-call initial_prompt
term-seeding + alias/phonetic fuzzy mention-counting (D-27.5). large-v3
default for the hosted/our-infra path; small floor for on-device
earnings.live.
Canonical schemas are the contract (no specs/ mirror). The engine imports
EarningsTranscriptSchema / EarningsFactSchema DIRECTLY from
mostlyright.core.schemas and re-exports them here — the canonical schemas ARE
the contract for both the local earnings.live path and the hosted serving
layer; there is no separate byte-equivalent mirror to keep in sync.
class mostlyright.weather.earnings.CaptureJob(ticker, provider, call_scheduled_at)
Section titled “class mostlyright.weather.earnings.CaptureJob(ticker, provider, call_scheduled_at)”Bases: object
A single due capture — one upcoming call inside the pre-call window.
call_scheduled_at : datetime
Section titled “call_scheduled_at : datetime”provider : str
Section titled “provider : str”ticker : str
Section titled “ticker : str”class mostlyright.weather.earnings.EarningsCalendarPoller(calendar_path=None)
Section titled “class mostlyright.weather.earnings.EarningsCalendarPoller(calendar_path=None)”Bases: object
Reads the codegen calendar seed; emits due capture jobs (D-27.7).
- Parameters: calendar_path (Path | None)
calendar : list[dict[str, str]]
Section titled “calendar : list[dict[str, str]]”The raw calendar rows (ticker / provider / call_scheduled_at
/ hq_timezone) from the codegen seed.
due_captures(now)
Section titled “due_captures(now)”Return capture jobs for calls inside the 1-2-day pre-call window.
A row is DUE when now <= call_scheduled_at <= now + 2 days — i.e. the
call is upcoming (not past) and within the look-ahead window. Calls
further out (a week early) or already elapsed are excluded, so the
capture fleet opens jobs only for the imminent cohort (RESEARCH-MARKETS
§1.3). now MUST be tz-aware (the SDK’s tz-aware discipline — a naive
instant would mis-order against the UTC call times and silently skip or
over-fire).
- Return type:
list[CaptureJob] - Parameters: now (datetime)
class mostlyright.weather.earnings.EarningsFactSchema
Section titled “class mostlyright.weather.earnings.EarningsFactSchema”Bases: Schema
schema.earnings_fact.v1 — one row per counted mention occurrence.
Carries the six RESEARCH-MARKETS §2 taxonomy dimensions (term match rule,
counting mode, speaker scope, window scope, time, tie-break/resolution) plus
the D-27.11 role_source provenance and the derived kalshi_counted
flag, so the SAME fact rows resolve correctly under each venue’s wording.
mention_count is the integer PRIMARY tally; the boolean (“said ≥ 1”) is
derived as mention_count >= 1 — storing only a bool cannot settle
Polymarket “say X 5+ times” threshold brackets (RESEARCH-MARKETS §2.1(2)).
COLUMNS : ClassVar[list[ColumnSpec]] = [ColumnSpec(name=‘ticker’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=”), ColumnSpec(name=‘call_id’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘provider event id for the call’), ColumnSpec(name=‘term_canonical’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘canonical market term (§2.1(3) term.canonical)’), ColumnSpec(name=‘term_accepted_forms’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘JSON-encoded list of accepted surface forms (exploded slash + plural/possessive) — §2.1(3) term.accepted_forms’), ColumnSpec(name=‘term_match_rule’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘exact’, ‘plural_possessive_ok_no_tense’, ‘lemma’, ‘regex’), notes=‘§2.1(3) term.match_rule (plural/possessive OK, NOT tense)’), ColumnSpec(name=‘compound_type’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘standalone’, ‘open’, ‘hyphenated’, ‘closed’, ‘affix_derivation’), notes=“D-30 §2.1(3) per-occurrence compound axis — SEPARATE from term_match_rule (do NOT overload MATCH_RULE_VALUES). standalone/open/hyphenated auto-count on both venues; closed is Polymarket candidate-only + Kalshi-No; affix_derivation counts for neither. Nullable: pre-fix rows omit it (default ‘standalone’)”), ColumnSpec(name=‘matched_surface_form’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=“the actually-spoken string (§2.1(3)) — kept verbatim so each occurrence is auditable against each venue’s stricter/looser rule”), ColumnSpec(name=‘mention_count’, dtype=‘int64’, units=None, nullable=False, enum_values=None, notes=‘PRIMARY integer tally (§2.1(2)); boolean is derived as >= 1 — storing only a bool cannot settle threshold brackets’), ColumnSpec(name=‘counting_mode’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘boolean_ge1’, ‘threshold_ge_n’, ‘exact_n’, ‘range’), notes=‘§2.1(2) counting_mode; boolean markets = boolean_ge1 (n=1)’), ColumnSpec(name=‘threshold_n’, dtype=‘int64’, units=None, nullable=True, enum_values=None, notes=‘§2.1(2) threshold_n (inclusive >= N); null for non-threshold modes’), ColumnSpec(name=‘speaker_role’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘company_executive’, ‘company_ir’, ‘operator_ir’, ‘operator_moderator’, ‘sell_side_analyst’, ‘other_external’, ‘unknown’), notes=‘§2.1(4) speaker_role — drives Kalshi/Polymarket scope divergence’), ColumnSpec(name=‘speaker_name’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=‘§2.1(4) speaker_name; nullable when unattributed’), ColumnSpec(name=‘role_source’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘transcript_structural’, ‘transcript_self_id’, ‘roster_match’, ‘diarization_advisory’), notes=‘D-27.11 provenance of the role attribution; only the three transcript-anchored values are Kalshi-countable (diarization is advisory only)’), ColumnSpec(name=‘segment’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘operator_intro’, ‘prepared_remarks’, ‘qa’, ‘closing’), notes=‘§2.1(5) call segment of the occurrence’), ColumnSpec(name=‘offset_seconds’, dtype=‘int64’, units=‘seconds’, nullable=True, enum_values=None, notes=‘§2.1(5) seconds into the call (audit trail); nullable’), ColumnSpec(name=‘confidence’, dtype=‘float64’, units=None, nullable=False, enum_values=None, notes=‘0..1 STT/attribution confidence (§2.1(6)) — flags borderline hits’), ColumnSpec(name=‘window_scope’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘full_call’, ‘prepared_remarks_only’, ‘qa_only’, ‘press_release_only’, ‘full_event_incl_release’), notes=‘§2.1(5) time-window scope a market resolves over’), ColumnSpec(name=‘resolution_status’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘pending’, ‘provisional’, ‘resolved_yes’, ‘resolved_no’, ‘no_qualifying_event’, ‘voided’, ‘disputed’), notes=“§2.1(6) resolution_status; ‘provisional’ = live early-signal delta (27-10, D-27.16) — NOT a settlement/backtest source”), ColumnSpec(name=‘kalshi_counted’, dtype=‘bool’, units=None, nullable=False, enum_values=None, notes=‘derived via validate_kalshi_counted_occurrence (D-27.11 fail-closed) — True iff role_source + speaker_role are anchorable’), ColumnSpec(name=‘is_final’, dtype=‘bool’, units=None, nullable=True, enum_values=None, notes=‘STT-segment finality ONLY (D-27.14/D-27.16); a provisional fact delta is is_final=True. NEVER gates settlement authority. Optional — batch rows omit/default True’), ColumnSpec(name=‘spoken_at’, dtype=‘timestamp_utc’, units=None, nullable=True, enum_values=None, notes=‘aired/event_time wallclock of the words (27-10, D-27.16); optional streaming marker — null on batch rows’), ColumnSpec(name=‘event_time’, dtype=‘timestamp_utc’, units=None, nullable=False, enum_values=None, notes=‘call air time (event-time)’), ColumnSpec(name=‘as_of_time’, dtype=‘timestamp_utc’, units=None, nullable=True, enum_values=None, notes=‘knowledge-time = transcript availability post-call (NOT event_date); for a live row stamped at STT-finalization/publish time and >= spoken_at (D-27.16); nullable’), ColumnSpec(name=‘source’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=“per-row source-identity overlay == ‘earnings_call’ (D-27.2)”), ColumnSpec(name=‘delivery’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘live’, ‘hosted’), notes=‘delivery-channel lineage {live,hosted}; NOT source identity (D-27.2)’)]
Section titled “COLUMNS : ClassVar[list[ColumnSpec]] = [ColumnSpec(name=‘ticker’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=”), ColumnSpec(name=‘call_id’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘provider event id for the call’), ColumnSpec(name=‘term_canonical’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘canonical market term (§2.1(3) term.canonical)’), ColumnSpec(name=‘term_accepted_forms’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘JSON-encoded list of accepted surface forms (exploded slash + plural/possessive) — §2.1(3) term.accepted_forms’), ColumnSpec(name=‘term_match_rule’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘exact’, ‘plural_possessive_ok_no_tense’, ‘lemma’, ‘regex’), notes=‘§2.1(3) term.match_rule (plural/possessive OK, NOT tense)’), ColumnSpec(name=‘compound_type’, dtype=‘enum’, units=None, nullable=True, enum_values=(‘standalone’, ‘open’, ‘hyphenated’, ‘closed’, ‘affix_derivation’), notes=“D-30 §2.1(3) per-occurrence compound axis — SEPARATE from term_match_rule (do NOT overload MATCH_RULE_VALUES). standalone/open/hyphenated auto-count on both venues; closed is Polymarket candidate-only + Kalshi-No; affix_derivation counts for neither. Nullable: pre-fix rows omit it (default ‘standalone’)”), ColumnSpec(name=‘matched_surface_form’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=“the actually-spoken string (§2.1(3)) — kept verbatim so each occurrence is auditable against each venue’s stricter/looser rule”), ColumnSpec(name=‘mention_count’, dtype=‘int64’, units=None, nullable=False, enum_values=None, notes=‘PRIMARY integer tally (§2.1(2)); boolean is derived as >= 1 — storing only a bool cannot settle threshold brackets’), ColumnSpec(name=‘counting_mode’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘boolean_ge1’, ‘threshold_ge_n’, ‘exact_n’, ‘range’), notes=‘§2.1(2) counting_mode; boolean markets = boolean_ge1 (n=1)’), ColumnSpec(name=‘threshold_n’, dtype=‘int64’, units=None, nullable=True, enum_values=None, notes=‘§2.1(2) threshold_n (inclusive >= N); null for non-threshold modes’), ColumnSpec(name=‘speaker_role’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘company_executive’, ‘company_ir’, ‘operator_ir’, ‘operator_moderator’, ‘sell_side_analyst’, ‘other_external’, ‘unknown’), notes=‘§2.1(4) speaker_role — drives Kalshi/Polymarket scope divergence’), ColumnSpec(name=‘speaker_name’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=‘§2.1(4) speaker_name; nullable when unattributed’), ColumnSpec(name=‘role_source’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘transcript_structural’, ‘transcript_self_id’, ‘roster_match’, ‘diarization_advisory’), notes=‘D-27.11 provenance of the role attribution; only the three transcript-anchored values are Kalshi-countable (diarization is advisory only)’), ColumnSpec(name=‘segment’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘operator_intro’, ‘prepared_remarks’, ‘qa’, ‘closing’), notes=‘§2.1(5) call segment of the occurrence’), ColumnSpec(name=‘offset_seconds’, dtype=‘int64’, units=‘seconds’, nullable=True, enum_values=None, notes=‘§2.1(5) seconds into the call (audit trail); nullable’), ColumnSpec(name=‘confidence’, dtype=‘float64’, units=None, nullable=False, enum_values=None, notes=‘0..1 STT/attribution confidence (§2.1(6)) — flags borderline hits’), ColumnSpec(name=‘window_scope’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘full_call’, ‘prepared_remarks_only’, ‘qa_only’, ‘press_release_only’, ‘full_event_incl_release’), notes=‘§2.1(5) time-window scope a market resolves over’), ColumnSpec(name=‘resolution_status’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘pending’, ‘provisional’, ‘resolved_yes’, ‘resolved_no’, ‘no_qualifying_event’, ‘voided’, ‘disputed’), notes=“§2.1(6) resolution_status; ‘provisional’ = live early-signal delta (27-10, D-27.16) — NOT a settlement/backtest source”), ColumnSpec(name=‘kalshi_counted’, dtype=‘bool’, units=None, nullable=False, enum_values=None, notes=‘derived via validate_kalshi_counted_occurrence (D-27.11 fail-closed) — True iff role_source + speaker_role are anchorable’), ColumnSpec(name=‘is_final’, dtype=‘bool’, units=None, nullable=True, enum_values=None, notes=‘STT-segment finality ONLY (D-27.14/D-27.16); a provisional fact delta is is_final=True. NEVER gates settlement authority. Optional — batch rows omit/default True’), ColumnSpec(name=‘spoken_at’, dtype=‘timestamp_utc’, units=None, nullable=True, enum_values=None, notes=‘aired/event_time wallclock of the words (27-10, D-27.16); optional streaming marker — null on batch rows’), ColumnSpec(name=‘event_time’, dtype=‘timestamp_utc’, units=None, nullable=False, enum_values=None, notes=‘call air time (event-time)’), ColumnSpec(name=‘as_of_time’, dtype=‘timestamp_utc’, units=None, nullable=True, enum_values=None, notes=‘knowledge-time = transcript availability post-call (NOT event_date); for a live row stamped at STT-finalization/publish time and >= spoken_at (D-27.16); nullable’), ColumnSpec(name=‘source’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=“per-row source-identity overlay == ‘earnings_call’ (D-27.2)”), ColumnSpec(name=‘delivery’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘live’, ‘hosted’), notes=‘delivery-channel lineage {live,hosted}; NOT source identity (D-27.2)’)]”schema_id : ClassVar[str] = ‘schema.earnings_fact.v1’
Section titled “schema_id : ClassVar[str] = ‘schema.earnings_fact.v1’”class mostlyright.weather.earnings.EarningsTranscriptSchema
Section titled “class mostlyright.weather.earnings.EarningsTranscriptSchema”Bases: Schema
schema.earnings_transcript.v1 — one row per transcript segment.
COLUMNS : ClassVar[list[ColumnSpec]] = [ColumnSpec(name=‘ticker’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=”), ColumnSpec(name=‘call_id’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘provider event id for the call’), ColumnSpec(name=‘segment_index’, dtype=‘int64’, units=None, nullable=False, enum_values=None, notes=‘ordinal index of the segment within the call’), ColumnSpec(name=‘segment’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘operator_intro’, ‘prepared_remarks’, ‘qa’, ‘closing’), notes=‘call segment (reuses earnings_fact.SEGMENT_VALUES)’), ColumnSpec(name=‘speaker_name’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=‘speaker name; nullable when unattributed’), ColumnSpec(name=‘speaker_role’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘company_executive’, ‘company_ir’, ‘operator_ir’, ‘operator_moderator’, ‘sell_side_analyst’, ‘other_external’, ‘unknown’), notes=‘speaker role (reuses earnings_fact.SPEAKER_ROLE_VALUES)’), ColumnSpec(name=‘text’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘verbatim segment text’), ColumnSpec(name=‘offset_seconds’, dtype=‘int64’, units=‘seconds’, nullable=False, enum_values=None, notes=‘seconds into the call where this segment begins’), ColumnSpec(name=‘is_final’, dtype=‘bool’, units=None, nullable=True, enum_values=None, notes=‘STT-segment finality ONLY (partial vs final text, D-27.14); NEVER gates settlement authority. Optional — batch rows omit/default True’), ColumnSpec(name=‘spoken_at’, dtype=‘timestamp_utc’, units=None, nullable=True, enum_values=None, notes=‘aired/event_time wallclock of the segment (27-10, D-27.16); optional streaming marker — null on batch rows’), ColumnSpec(name=‘stream_seq’, dtype=‘int64’, units=None, nullable=True, enum_values=None, notes=‘monotonic streaming sequence number (27-10); optional — absent on batch rows’), ColumnSpec(name=‘event_time’, dtype=‘timestamp_utc’, units=None, nullable=False, enum_values=None, notes=‘call air time (event-time)’), ColumnSpec(name=‘as_of_time’, dtype=‘timestamp_utc’, units=None, nullable=True, enum_values=None, notes=‘knowledge-time = transcript availability post-call (NOT event_date); for a live row stamped at STT-finalization/publish time and >= spoken_at (D-27.16); nullable’), ColumnSpec(name=‘source’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=“per-row source-identity overlay == ‘earnings_call’ (D-27.2)”), ColumnSpec(name=‘delivery’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘live’, ‘hosted’), notes=‘delivery-channel lineage {live,hosted}; NOT source identity (D-27.2)’)]
Section titled “COLUMNS : ClassVar[list[ColumnSpec]] = [ColumnSpec(name=‘ticker’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=”), ColumnSpec(name=‘call_id’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘provider event id for the call’), ColumnSpec(name=‘segment_index’, dtype=‘int64’, units=None, nullable=False, enum_values=None, notes=‘ordinal index of the segment within the call’), ColumnSpec(name=‘segment’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘operator_intro’, ‘prepared_remarks’, ‘qa’, ‘closing’), notes=‘call segment (reuses earnings_fact.SEGMENT_VALUES)’), ColumnSpec(name=‘speaker_name’, dtype=‘string’, units=None, nullable=True, enum_values=None, notes=‘speaker name; nullable when unattributed’), ColumnSpec(name=‘speaker_role’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘company_executive’, ‘company_ir’, ‘operator_ir’, ‘operator_moderator’, ‘sell_side_analyst’, ‘other_external’, ‘unknown’), notes=‘speaker role (reuses earnings_fact.SPEAKER_ROLE_VALUES)’), ColumnSpec(name=‘text’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=‘verbatim segment text’), ColumnSpec(name=‘offset_seconds’, dtype=‘int64’, units=‘seconds’, nullable=False, enum_values=None, notes=‘seconds into the call where this segment begins’), ColumnSpec(name=‘is_final’, dtype=‘bool’, units=None, nullable=True, enum_values=None, notes=‘STT-segment finality ONLY (partial vs final text, D-27.14); NEVER gates settlement authority. Optional — batch rows omit/default True’), ColumnSpec(name=‘spoken_at’, dtype=‘timestamp_utc’, units=None, nullable=True, enum_values=None, notes=‘aired/event_time wallclock of the segment (27-10, D-27.16); optional streaming marker — null on batch rows’), ColumnSpec(name=‘stream_seq’, dtype=‘int64’, units=None, nullable=True, enum_values=None, notes=‘monotonic streaming sequence number (27-10); optional — absent on batch rows’), ColumnSpec(name=‘event_time’, dtype=‘timestamp_utc’, units=None, nullable=False, enum_values=None, notes=‘call air time (event-time)’), ColumnSpec(name=‘as_of_time’, dtype=‘timestamp_utc’, units=None, nullable=True, enum_values=None, notes=‘knowledge-time = transcript availability post-call (NOT event_date); for a live row stamped at STT-finalization/publish time and >= spoken_at (D-27.16); nullable’), ColumnSpec(name=‘source’, dtype=‘string’, units=None, nullable=False, enum_values=None, notes=“per-row source-identity overlay == ‘earnings_call’ (D-27.2)”), ColumnSpec(name=‘delivery’, dtype=‘enum’, units=None, nullable=False, enum_values=(‘live’, ‘hosted’), notes=‘delivery-channel lineage {live,hosted}; NOT source identity (D-27.2)’)]”schema_id : ClassVar[str] = ‘schema.earnings_transcript.v1’
Section titled “schema_id : ClassVar[str] = ‘schema.earnings_transcript.v1’”class mostlyright.weather.earnings.EndOfCall(call_id)
Section titled “class mostlyright.weather.earnings.EndOfCall(call_id)”Bases: object
End-of-call control sentinel: the streaming engine finished call_id.
Published by SegmentBus.close() and delivered LAST to every live
subscriber so the 27-11 SSE route can emit a terminating end_of_call
frame and close the connection cleanly (no dangling generator / leaked
subscriber). It is a TEXT/control marker only — carries no audio (D-27.9).
- Parameters: call_id (str)
call_id : str
Section titled “call_id : str”class mostlyright.weather.earnings.FactDelta(term_canonical, matched_surface_form, mention_count, speaker_role, role_source, speaker_name, kalshi_counted, is_final, spoken_at, stream_seq, compound_type=‘standalone’, resolution_status=‘provisional’, source=‘earnings_call’)
Section titled “class mostlyright.weather.earnings.FactDelta(term_canonical, matched_surface_form, mention_count, speaker_role, role_source, speaker_name, kalshi_counted, is_final, spoken_at, stream_seq, compound_type=‘standalone’, resolution_status=‘provisional’, source=‘earnings_call’)”Bases: object
A provisional live fact delta counted off a FINAL segment (never a partial).
Shaped for schema.earnings_fact.v1: resolution_status="provisional"
(live early-signal — NOT a settlement source), is_final=True (STT
finality — orthogonal to authority), kalshi_counted derived via the
unchanged fail-closed validate_kalshi_counted_occurrence() (D-27.11,
mode-agnostic). TEXT/facts only — no audio (D-27.9).
compound_type (D-30, review F1) is the per-delta compound axis — one
delta per (term, compound_type), never an aggregate mixing types, so the
venue filters in fact_builder apply row-wise (closed candidates surface
for Polymarket human review; Kalshi-No on closed). ADDITIVE with default
"standalone": an existing SSE consumer or a persisted pre-fix delta is
unaffected (standalone counts for both venues exactly as before the axis).
- Parameters:
compound_type : str
Section titled “compound_type : str”is_final : bool
Section titled “is_final : bool”kalshi_counted : bool
Section titled “kalshi_counted : bool”matched_surface_form : str
Section titled “matched_surface_form : str”mention_count : int
Section titled “mention_count : int”resolution_status : str
Section titled “resolution_status : str”role_source : str
Section titled “role_source : str”source : str
Section titled “source : str”speaker_name : str | None
Section titled “speaker_name : str | None”speaker_role : str
Section titled “speaker_role : str”spoken_at : float
Section titled “spoken_at : float”stream_seq : int
Section titled “stream_seq : int”term_canonical : str
Section titled “term_canonical : str”to_stt_count(, turn_index=None)
Section titled “to_stt_count(, turn_index=None)”Map this delta to a build_fact_rows stt_counts occurrence record.
The propagation seam (review F1): compound_type survives from the
live classifier through the occurrence record into the fact row, so the
venue filters + the fail-loud closed-candidate resolution operate on the
SAME axis end-to-end. turn_index (when known) links the occurrence
to the role-parser turns list so build_fact_rows re-derives the
speaker scope from the authoritative turn.
TEMPORAL MAPPING (review R2-F3): this delta’s spoken_at is an
ENGINE-RELATIVE float (seconds into the stream, e.g. 12.5), NOT a
wallclock. It maps into offset_seconds — the schema’s
engine-relative int audit field, which build_fact_rows already
accepts. It is NEVER emitted as the occurrence’s spoken_at: that
schema column is timestamp_utc and pyarrow silently coerces a float
to microseconds-after-epoch, persisting 1970-01-01 00:00:00.000012+00:00 as the temporal audit marker. spoken_at is
left ABSENT (the column is nullable); a caller holding a genuine
tz-aware wallclock sets it on the occurrence record explicitly —
build_fact_rows fail-louds on any non-tz-aware-datetime value.
class mostlyright.weather.earnings.FactLedger(root=None)
Section titled “class mostlyright.weather.earnings.FactLedger(root=None)”Bases: _ParquetLedger
Append-only schema.earnings_fact.v1 counted-mention ledger (no audio).
- Parameters: root (Path | str | None)
class mostlyright.weather.earnings.RedisSegmentBus(*args, **kwargs)
Section titled “class mostlyright.weather.earnings.RedisSegmentBus(*args, **kwargs)”Bases: object
RESERVED multi-node seam (D-27.17) — NOT implemented in v1.
A Redis-pub/sub backplane behind the SAME SegmentBusProtocol
publish/subscribe interface, so a multi-node deployment can fan segments
across processes without changing the streaming engine or the SSE endpoint.
Reserved only — constructing it raises NotImplementedError in v1
(the in-process SegmentBus is the shipped implementation).
class mostlyright.weather.earnings.ResumeIncomplete(from_seq, earliest_retained_seq)
Section titled “class mostlyright.weather.earnings.ResumeIncomplete(from_seq, earliest_retained_seq)”Bases: object
Resume marker: from_seq predates the ring buffer’s earliest retained seq.
Yielded FIRST to a resubscribing consumer whose requested from_seq is
older than anything the bounded ring buffer still holds — the gap between
from_seq and earliest_retained_seq cannot be replayed from the bus,
so the consumer MUST reconcile from the authoritative post-call ledger
(27-04). This is an EXPLICIT signal, never a silent gap (codex P2).
earliest_retained_seq : int
Section titled “earliest_retained_seq : int”from_seq : int
Section titled “from_seq : int”class mostlyright.weather.earnings.RoleParser(roster=None)
Section titled “class mostlyright.weather.earnings.RoleParser(roster=None)”Bases: object
Attribute transcript turns to speaker roles from TEXT cues only (D-27.11).
Construct with the published participant roster ((name, firm) pairs
or RosterEntry rows). attribute_turns walks a segmented
transcript and assigns each turn a speaker_role + role_source,
resolving mangled analyst surnames via fuzzy_match_surname() gated on
the firm token. A turn with no structural cue and no roster hit is left
role_source="diarization_advisory" — NEVER a Kalshi-countable source.
attribute_turns(transcript, roster=None)
Section titled “attribute_turns(transcript, roster=None)”Attribute every turn in transcript to a role from TEXT cues.
transcript is either the raw transcript text (parsed for operator
announcements + self-IDs + label lines) OR a list of pre-segmented turn
dicts ({"speaker_name": ..., "label": ..., "text": ...}). roster
overrides the instance roster for this call.
Each returned Turn carries speaker_role + role_source.
Un-anchorable turns get role_source="diarization_advisory".
class mostlyright.weather.earnings.RosterEntry(name, firm, role=‘unknown’)
Section titled “class mostlyright.weather.earnings.RosterEntry(name, firm, role=‘unknown’)”Bases: object
A published-participant roster row: canonical name, firm, and role.
role is one of the SPEAKER_ROLE_VALUES (e.g. sell_side_analyst
for an analyst, company_executive for a named exec). The firm token is
the fuzzy-match GATE — a surname is only repaired against entries sharing the
cleanly-transcribed firm.
class mostlyright.weather.earnings.Segment(text, is_final, spoken_at, stream_seq, knowledge_time, fact_deltas=)
Section titled “class mostlyright.weather.earnings.Segment(text, is_final, spoken_at, stream_seq, knowledge_time, fact_deltas=)”Bases: object
One streaming transcript segment — TEXT ONLY (never audio, D-27.9).
is_final is STT-segment finality ONLY (partial vs final text, D-27.14);
it NEVER gates settlement authority. spoken_at is the aired/event-time
wallclock of the window’s start; knowledge_time is the STT-finalization/
publish wallclock (>= spoken_at, D-27.16). fact_deltas is populated
on FINAL segments ONLY.
- Parameters:
fact_deltas : list[FactDelta]
Section titled “fact_deltas : list[FactDelta]”is_final : bool
Section titled “is_final : bool”knowledge_time : float
Section titled “knowledge_time : float”spoken_at : float
Section titled “spoken_at : float”stream_seq : int
Section titled “stream_seq : int”class mostlyright.weather.earnings.SegmentBus(, subscriber_queue_maxsize=256, ring_buffer_size=128, subscriber_hard_maxsize=None)
Section titled “class mostlyright.weather.earnings.SegmentBus(, subscriber_queue_maxsize=256, ring_buffer_size=128, subscriber_hard_maxsize=None)”Bases: object
In-process asyncio per-call pub/sub bus (v1; Redis is a reserved seam).
- Parameters:
async close(call_id)
Section titled “async close(call_id)”Signal end-of-call: deliver an EndOfCall marker to subscribers.
Each live subscriber receives the marker LAST (after any queued items);
the SSE route yields it as a terminating end_of_call frame then closes
cleanly. Idempotent — closing a call with no subscribers is a no-op.
is_closed(call_id)
Section titled “is_closed(call_id)”Whether call_id has emitted end-of-call (a finished call).
async publish(call_id, item)
Section titled “async publish(call_id, item)”Publish item to call_id — fan-out + ring-buffer the finals.
Rejects audio bytes / non-Segment-or-FactDelta objects (D-27.9). Appends FINAL items (final Segment or any FactDelta) to the per-call ring buffer. Puts to every subscriber queue with drop-oldest-partial backpressure; the publisher never blocks.
subscribe(call_id, from_seq=None)
Section titled “subscribe(call_id, from_seq=None)”Subscribe to call_id; return an async generator of items.
When from_seq is given, first replays ring-buffer FINALs with
stream_seq > from_seq (gap recovery). If from_seq predates the
ring buffer’s earliest retained seq, yields a ResumeIncomplete
marker FIRST (reconcile from the ledger — never a silent gap). When
from_seq is None, backfills the bounded ring buffer of recent finals.
Then drains the live queue.
- Return type:
AsyncIterator[Segment|FactDelta|ResumeIncomplete|EndOfCall] - Parameters:
subscriber_count(call_id)
Section titled “subscriber_count(call_id)”Number of live subscribers on call_id (0 after clean teardown).
class mostlyright.weather.earnings.SegmentBusProtocol(*args, **kwargs)
Section titled “class mostlyright.weather.earnings.SegmentBusProtocol(*args, **kwargs)”Bases: Protocol
The publish/subscribe contract both the in-process + Redis buses satisfy.
async publish(call_id, item)
Section titled “async publish(call_id, item)”subscribe(call_id, from_seq=None)
Section titled “subscribe(call_id, from_seq=None)”- Return type:
AsyncIterator[Segment|FactDelta|ResumeIncomplete|EndOfCall] - Parameters:
class mostlyright.weather.earnings.StreamingTranscriber(, transcriber=None, initial_prompt_terms=None, market_terms=None, turn_provider=None, model_size=‘small’)
Section titled “class mostlyright.weather.earnings.StreamingTranscriber(, transcriber=None, initial_prompt_terms=None, market_terms=None, turn_provider=None, model_size=‘small’)”Bases: object
VAD-chunked streaming STT → partial/final segments + final-only fact deltas.
- Parameters:
- transcriber (
Callable[...,str] |None) – A callable(window_pcm, *, initial_prompt) -> text. Injected so unit tests stub faster-whisper. WhenNone, a lazy faster-whisper transcriber is built (DEFERRED / operator-only path). - initial_prompt_terms (
Sequence[str] |None) – The market strike terms the per-callinitial_promptis seeded from (reuses 27-03seed_initial_prompt()). - market_terms (
Sequence[Mapping[str,object]] |None) – Per-term market specs (term_canonicalat minimum) the final-only counter runs over. When empty, no fact deltas are produced. - turn_provider (
Callable[[Segment],Turn|None] |None) – Maps a segment to the role-parserTurn(speaker_role / role_source) driving the fail-closed Kalshi rule. Defaults to anunknown/diarization_advisoryturn (Kalshi-excluded — fail-closed). - model_size (str)
- transcriber (
fact_deltas : list[FactDelta]
Section titled “fact_deltas : list[FactDelta]”All fact deltas emitted this run (final-only) — inspectable by callers.
run(frame_iter)
Section titled “run(frame_iter)”Consume (pcm_frame, spoken_at) frames → yield partial/final Segments.
For each VAD speech run: yields ONE revisable partial per accumulated
window (is_final=False), then ONE final (is_final=True) on the
speech-end boundary. The FINAL carries the STABILISED text of the ENTIRE
run (every window’s transcription, overlap de-duplicated), NOT just the
post-flush tail — so a term spoken early in a continuous run is counted
exactly once. Fact deltas are computed on the FINAL segment only and
appended to fact_deltas (and to the final segment’s
fact_deltas list).
class mostlyright.weather.earnings.TranscriptLedger(root=None)
Section titled “class mostlyright.weather.earnings.TranscriptLedger(root=None)”Bases: _ParquetLedger
Append-only schema.earnings_transcript.v1 segment ledger (no audio).
- Parameters: root (Path | str | None)
class mostlyright.weather.earnings.Turn(speaker_name, speaker_role, role_source, firm=None, text=”, confidence=1.0)
Section titled “class mostlyright.weather.earnings.Turn(speaker_name, speaker_role, role_source, firm=None, text=”, confidence=1.0)”Bases: object
A single attributed transcript turn.
speaker_role is a SPEAKER_ROLE_VALUES member; role_source is a
ROLE_SOURCE_VALUES member. An un-anchorable turn carries
role_source="diarization_advisory" (or "unknown") — never a
Kalshi-countable source, so the downstream fail-closed filter excludes it
from the Kalshi count.
- Parameters:
confidence : float
Section titled “confidence : float”role_source : str
Section titled “role_source : str”speaker_name : str | None
Section titled “speaker_name : str | None”speaker_role : str
Section titled “speaker_role : str”mostlyright.weather.earnings.apply_kalshi_filter(rows)
Section titled “mostlyright.weather.earnings.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.build_fact_rows(stt_counts, turns, market_terms, , ticker, call_id, event_time=None)
Section titled “mostlyright.weather.earnings.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.fuzzy_match_surname(spoken, roster, firm_token, , cutoff=0.72)
Section titled “mostlyright.weather.earnings.fuzzy_match_surname(spoken, roster, firm_token, , cutoff=0.72)”Repair a mangled analyst surname against the published roster.
spoken is the (possibly mis-transcribed) surname as heard —
"DeFucci" for "DiFucci", "Elnick" for "Zelnick". roster
is the published participant list as (name, firm) pairs (or
RosterEntry rows). firm_token is the cleanly-transcribed firm —
the fuzzy match is GATED on it: only roster entries whose firm matches
firm_token (exact, normalized) are candidates, so a close surname in the
WRONG firm can never be adopted (the cross-firm mis-attribution hazard).
Returns the roster’s CANONICAL surname on a confident match, else None.
Uses difflib.get_close_matches() (stdlib): the surname-repair job is
tiny, and difflib’s SequenceMatcher ratio comfortably resolves the 1-char /
phonetic drifts observed (DeFucci→DiFucci ratio ~0.86, Elnick→Zelnick
~0.77). No third-party fuzzy dependency is pulled (no new-dep legitimacy
gate).
mostlyright.weather.earnings.parse_operator_announcements(text)
Section titled “mostlyright.weather.earnings.parse_operator_announcements(text)”Extract operator analyst hand-off announcements from text.
Returns one dict per announcement:
{"name": "John DiFucci", "firm": "Guggenheim", "role_source": "transcript_structural"}The operator names every analyst by name+firm; this is the most reliable
transcript-anchored role cue (§1). The extracted analyst is a
sell_side_analyst — the caller assigns the role. Firm is captured
verbatim so it can gate a downstream roster fuzzy-match on a mangled surname.
Modules
Section titled “Modules”calendar_poller | Venue-derived earnings-capture trigger (Phase 27, 27-03; D-27.7). |
|---|---|
capture | Earnings webcast capture fleet (Phase 27, 27-03). |
fact_builder | Earnings fact-row builder + fail-closed Kalshi filter (Phase 27, 27-04). |
ledger | Append-only transcript + fact parquet ledger (Phase 27, 27-04). |
live_capture_runner | Live capture session runner + live de-risk spike harness (Phase 27, 27-09 W5). |
provenance | Earnings provenance + retention contract (Phase 27, 27-08). |
role_parser | Transcript-anchored role-attribution parser (Phase 27, 27-04). |
segment_bus | In-process asyncio segment/fact pub-sub bus (Phase 27, 27-10 Task 3). |
streaming_transcriber | Streaming STT engine (Phase 27, 27-10 Task 2). |
stt | faster-whisper STT transcriber + alias-aware mention counter (Phase 27, 27-03). |