Skip to content

mostlyright.finance.transcripts

mostlyright.finance.transcripts — the earnings-call transcript pipeline.

This sub-namespace provides the complete earnings-call research pipeline:

Engine (capture → STT → fact/ledger → segment bus) : The on-device capture + STT engine for the transcripts.live source and the engine used by the default transcripts.hosted path. Heavy runtime dependencies (faster-whisper for STT, av for the transient audio extract) live behind the [transcripts] optional extra and are lazy-imported inside the capture/STT methods, so importing this module and running the unit tests needs only the base finance deps. Captured audio is a transient artifact, deleted after transcription; only transcript text and derived facts survive.

Adapter + stream (adapter, _stream) : The thin EarningsAdapter consumer/parser and the SSE consume_sse reader.

Market resolution (resolver, registries, pit, polymarket_derive) : The prediction-market earnings-mention universe: resolve a Kalshi KXEARNINGSMENTION{TICKER} / Polymarket “will say ” series, the codegen source-of-truth registries + calendar seed, and the point-in-time helpers (knowledge_time = transcript availability — the leakage cutoff).

Canonical schemas are the contract. The engine imports EarningsTranscriptSchema / EarningsFactSchema directly from mostlyright.core.schemas and re-exports them here. Those schemas are the contract for both the local transcripts.live path and the hosted service; there is no separate byte-equivalent mirror to keep in sync.

class mostlyright.finance.transcripts.EarningsFactSchema

Section titled “class mostlyright.finance.transcripts.EarningsFactSchema”

Bases: Schema

schema.finance.fact.v1 — one row per counted mention occurrence.

Carries the six taxonomy dimensions (term match rule, counting mode, speaker scope, window scope, time, tie-break/resolution) plus the 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 primary integer tally; the boolean (“said at least once”) is derived as mention_count >= 1. Storing only a bool cannot settle Polymarket “say X 5+ times” threshold brackets.

class mostlyright.finance.transcripts.EarningsResolution(ticker, target_word, event_date, resolution_rule, resolution_status=‘qualifying_event’)

Section titled “class mostlyright.finance.transcripts.EarningsResolution(ticker, target_word, event_date, resolution_rule, resolution_status=‘qualifying_event’)”

Bases: object

The frozen tuple a Kalshi earnings-mention contract resolves to.

Shaped like NHighResolution: an immutable (ticker, target_word, event_date, resolution_rule) carrier, so a resolution cannot be mutated downstream. The TypeScript twin freezes the equivalent object with Object.freeze.

  • Parameters:
    • ticker (str)
    • target_word (str)
    • event_date (date)
    • resolution_rule (str)
    • resolution_status (str)

Whether a qualifying call exists for this date. "qualifying_event" for a normal resolution; "no_qualifying_event" when the Polymarket derive sees a postponed or cancelled call. It carries a default so the Kalshi resolve path never has to set it.

class mostlyright.finance.transcripts.EarningsTranscriptSchema

Section titled “class mostlyright.finance.transcripts.EarningsTranscriptSchema”

Bases: Schema

schema.finance.transcript.v1 — one row per transcript segment.

class mostlyright.finance.transcripts.EndOfCall(call_id)

Section titled “class mostlyright.finance.transcripts.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 SSE route can emit a terminating end_of_call frame and close the connection cleanly, leaving no dangling generator or leaked subscriber. It is a text/control marker and carries no audio.

  • Parameters: call_id (str)

class mostlyright.finance.transcripts.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.finance.transcripts.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.finance.fact.v1: resolution_status="provisional" marks it an early live signal rather than a settlement source, is_final=True is STT finality and is orthogonal to authority, and kalshi_counted is derived through the fail-closed validate_kalshi_counted_occurrence(). Text and facts only, no audio.

compound_type is per delta: one delta per (term, compound_type), never an aggregate mixing types, so the venue filters in fact_builder apply row-wise (closed candidates go to Polymarket human review; Kalshi resolves No on closed). It defaults to "standalone", so an existing SSE consumer or a persisted delta written before the field existed counts for both venues exactly as it did before.

  • Parameters:
    • term_canonical (str)
    • matched_surface_form (str)
    • mention_count (int)
    • speaker_role (str)
    • role_source (str)
    • speaker_name (str | None)
    • kalshi_counted (bool)
    • is_final (bool)
    • spoken_at (float)
    • stream_seq (int)
    • compound_type (str)
    • resolution_status (str)
    • source (str)

Map this delta to a build_fact_rows stt_counts occurrence record.

compound_type survives from the live classifier through the occurrence record into the fact row, so the venue filters and the fail-loud closed-candidate resolution operate on the same value 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: this delta’s spoken_at is an engine-relative float (seconds into the stream, for example 12.5), not a wallclock. It maps into offset_seconds, the schema’s engine-relative integer audit field that 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, since the column is nullable; a caller holding a genuine tz-aware wallclock sets it on the occurrence record explicitly, and build_fact_rows fails loud on any value that is not a tz-aware datetime.

class mostlyright.finance.transcripts.FactLedger(root=None)

Section titled “class mostlyright.finance.transcripts.FactLedger(root=None)”

Bases: _ParquetLedger

Append-only schema.finance.fact.v1 counted-mention ledger (no audio).

  • Parameters: root (Path | str | None)

class mostlyright.finance.transcripts.ResumeIncomplete(from_seq, earliest_retained_seq)

Section titled “class mostlyright.finance.transcripts.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. This is an explicit signal, never a silent gap.

  • Parameters:
    • from_seq (int)
    • earliest_retained_seq (int)

class mostlyright.finance.transcripts.RoleParser(roster=None)

Section titled “class mostlyright.finance.transcripts.RoleParser(roster=None)”

Bases: object

Attribute transcript turns to speaker roles from text cues only.

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 every turn in transcript to a role from text cues.

transcript is either the raw transcript text (parsed for operator announcements, self-identifications, and 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.finance.transcripts.RosterEntry(name, firm, role=‘unknown’)

Section titled “class mostlyright.finance.transcripts.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 (for example sell_side_analyst for an analyst, company_executive for a named executive). The firm token gates the fuzzy match: a surname is only repaired against entries sharing the cleanly-transcribed firm.

  • Parameters:

class mostlyright.finance.transcripts.Segment(text, is_final, spoken_at, stream_seq, knowledge_time, fact_deltas=)

Section titled “class mostlyright.finance.transcripts.Segment(text, is_final, spoken_at, stream_seq, knowledge_time, fact_deltas=)”

Bases: object

One streaming transcript segment: text only, never audio.

is_final is STT-segment finality only (partial versus final text) and 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). fact_deltas is populated on final segments only.

class mostlyright.finance.transcripts.SegmentBus(, subscriber_queue_maxsize=256, ring_buffer_size=128, subscriber_hard_maxsize=None)

Section titled “class mostlyright.finance.transcripts.SegmentBus(, subscriber_queue_maxsize=256, ring_buffer_size=128, subscriber_hard_maxsize=None)”

Bases: object

In-process asyncio per-call pub/sub bus; single process only.

  • Parameters:
    • subscriber_queue_maxsize (int) – Bounded per-subscriber buffer depth; on overflow the oldest partial is dropped.
    • ring_buffer_size (int) – Per-call ring buffer depth of the last K final events (resume backfill).
    • subscriber_hard_maxsize (int | None)

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 and then closes cleanly. Idempotent: closing a call with no subscribers is a no-op.

  • Return type: None
  • Parameters: call_id (str)

Whether call_id has emitted end-of-call (a finished call).

  • Return type: bool
  • Parameters: call_id (str)

Publish item to call_id — fan-out + ring-buffer the finals.

Rejects audio bytes and any object that is not a Segment or FactDelta. Appends final items (a final Segment or any FactDelta) to the per-call ring buffer, then offers to every subscriber buffer with drop-oldest-partial backpressure. The publisher never blocks.

Subscribe to call_id; return an async generator of items.

When from_seq is given, this first replays ring-buffer finals with stream_seq > from_seq, plus any fact delta at from_seq, which shares its parent segment’s seq and trails it on the wire (see _replay_after()). If from_seq predates the ring buffer’s earliest retained seq, a ResumeIncomplete marker is yielded first, telling the consumer to reconcile from the ledger rather than gapping silently. When from_seq is None, it backfills the bounded ring buffer of recent finals. It then drains the live buffer.

Number of live subscribers on call_id (0 after clean teardown).

  • Return type: int
  • Parameters: call_id (str)

class mostlyright.finance.transcripts.SegmentBusProtocol(*args, **kwargs)

Section titled “class mostlyright.finance.transcripts.SegmentBusProtocol(*args, **kwargs)”

Bases: Protocol

The publish/subscribe contract the in-process bus satisfies.

A future cross-process (Redis/Memorystore) backplane would implement this same interface, so a multi-node deployment can fan segments across processes without changing the streaming engine or the SSE endpoint.

class mostlyright.finance.transcripts.StreamingTranscriber(, transcriber=None, initial_prompt_terms=None, market_terms=None, turn_provider=None, model_size=‘small’)

Section titled “class mostlyright.finance.transcripts.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. Pass a streaming audio transcriber explicitly. Omitting it creates a placeholder that raises NotImplementedError when transcription begins.
    • initial_prompt_terms (Sequence[str] | None) – The market strike terms the per-call initial_prompt is seeded from (reuses seed_initial_prompt()).
    • market_terms (Sequence[Mapping[str, object]] | None) – Per-term market specs (term_canonical at 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-parser Turn (speaker_role / role_source) driving the fail-closed Kalshi rule. Defaults to an unknown / diarization_advisory turn (Kalshi-excluded — fail-closed).
    • model_size (str)

All fact deltas emitted this run (final-only) — inspectable by callers.

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 — or, for a run still open when the frames run out, at end of stream (a trailing silence frame is a caller convenience, never a precondition for a run being finalised and counted). The final segment carries the stabilised text of the entire run — every window’s transcription, with the 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.finance.transcripts.TranscriptLedger(root=None)

Section titled “class mostlyright.finance.transcripts.TranscriptLedger(root=None)”

Bases: _ParquetLedger

Append-only schema.finance.transcript.v1 segment ledger (no audio).

  • Parameters: root (Path | str | None)

class mostlyright.finance.transcripts.Turn(speaker_name, speaker_role, role_source, firm=None, text=”, confidence=1.0)

Section titled “class mostlyright.finance.transcripts.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:
    • speaker_name (str | None)
    • speaker_role (str)
    • role_source (str)
    • firm (str | None)
    • text (str)
    • confidence (float)

mostlyright.finance.transcripts.apply_kalshi_filter(rows)

Section titled “mostlyright.finance.transcripts.apply_kalshi_filter(rows)”

Set kalshi_counted on every row via the fail-closed rule.

kalshi_counted = validate_kalshi_counted_occurrence(role_source, speaker_role)True only when both the role_source and the 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 and does not mutate the inputs.

mostlyright.finance.transcripts.build_fact_rows(stt_counts, turns, market_terms, , ticker, call_id, event_time=None)

Section titled “mostlyright.finance.transcripts.build_fact_rows(stt_counts, turns, market_terms, , ticker, call_id, event_time=None)”

Build schema.finance.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.finance.transcripts.derive(event)

Section titled “mostlyright.finance.transcripts.derive(event)”

Derive a frozen EarningsResolution from a Polymarket event payload.

The payload is untrusted. The derive refuses (returns None) when:

  • the slug/title does not look like an earnings-mention market;
  • the ticker is missing or not in EARNINGS_SERIES_ROSTER;
  • a webcast_url is present but its host is not on WEBCAST_HOST_ALLOWLIST (refused before anything is derived);
  • target_word or event_date is missing or unparseable.

A postponed or cancelled call yields a resolution with resolution_status="no_qualifying_event".

mostlyright.finance.transcripts.detect_provider(webcast_url)

Section titled “mostlyright.finance.transcripts.detect_provider(webcast_url)”

Name the webcast provider for webcast_url, or None.

The host is first checked against WEBCAST_HOST_ALLOWLIST: a non-allowlisted host returns None and is never fingerprinted from a raw substring, so a hostile evil.example/q4inc cannot spoof a provider. An allowlisted host is then matched against WEBCAST_PROVIDER_FINGERPRINTS by host substring.

  • Return type: str | None
  • Returns: The canonical provider id ("q4" etc.), or None when the host is non-allowlisted or matches no fingerprint.
  • Parameters: webcast_url (str)

mostlyright.finance.transcripts.fuzzy_match_surname(spoken, roster, firm_token, , cutoff=0.72)

Section titled “mostlyright.finance.transcripts.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 and gates the fuzzy match: only roster entries whose firm matches firm_token (exact, normalized) are candidates, so a close surname at the wrong firm can never be adopted and cause a cross-firm mis-attribution.

Returns the roster’s canonical surname on a confident match, else None. Uses the stdlib difflib.get_close_matches(): the surname-repair job is small, and difflib’s SequenceMatcher ratio comfortably resolves the one-char and phonetic drifts observed (DeFucci→DiFucci ratio ~0.86, Elnick→Zelnick ~0.77), so no third-party fuzzy dependency is needed.

mostlyright.finance.transcripts.parse_operator_announcements(text)

Section titled “mostlyright.finance.transcripts.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 and firm; this is the most reliable transcript-anchored role cue. The extracted analyst is a sell_side_analyst, and the caller assigns the role. Firm is captured verbatim so it can gate a downstream roster fuzzy-match on a mangled surname.

mostlyright.finance.transcripts.resolve(contract_id, event_date, , target_word)

Section titled “mostlyright.finance.transcripts.resolve(contract_id, event_date, , target_word)”

Resolve a Kalshi earnings-mention contract to its frozen tuple.

The contract_id is the Kalshi market identifier — one of the three root variants KXEARNINGSMENTION<TICKER> (e.g. KXEARNINGSMENTIONNKE), KXMENTIONEARN<TICKER>, or the Berkshire fixed root KXBRKEM. The suffix is the ticker; it is validated against EARNINGS_SERIES_ROSTER.

  • Parameters:
    • contract_id (str) – Kalshi market identifier. Case-insensitive.
    • event_date (date) – The calendar date the call airs / the market settles for. Must be a datetime.date with no time component.
    • target_word (str) – The word/phrase the market resolves on. Required, non-empty.
  • Return type: EarningsResolution
  • Returns: A frozen EarningsResolution.
  • Raises:
    • TypeErrorcontract_id is not a string, event_date is a datetime (or any non-date), or target_word is not a string.
    • ValueErrorcontract_id matches no known root, the ticker suffix is empty, the ticker is not in EARNINGS_SERIES_ROSTER, or target_word is empty.
ModuleDescription
adapterEarnings catalog adapter.
captureEarnings webcast capture fleet.
catalogEarnings discovery-time membership registries.
fact_builderEarnings fact-row builder + fail-closed Kalshi filter.
ledgerAppend-only transcript + fact parquet ledger.
pitPoint-in-time alignment + leakage wiring for earnings facts.
polymarket_derivePolymarket earnings-mention derive + webcast provider fingerprint.
registriesEarnings codegen registries — source-of-truth dicts.
resolverKalshi earnings-mention resolver.
role_parserTranscript-anchored role-attribution parser.
segment_busIn-process asyncio segment/fact pub-sub bus.
streaming_transcriberStreaming STT engine.
sttfaster-whisper STT transcriber + alias-aware mention counter.