mostlyright.weather.catalog.earnings
mostlyright.weather.catalog.earnings
Section titled “mostlyright.weather.catalog.earnings”Earnings catalog adapter (Phase 27, 27-06).
The thin SDK CONSUMER of the earnings-audio Tier-2 feed (D-27.1 “satellites
produce, SDKs consume”). Mirrors mostlyright.weather.catalog.awc exactly:
SUPPORTED_SOURCES at class level, from_rows projecting parser-output rows
to a canonical schema + overlay columns, bottom-of-file register_adapter.
Two delivery channels, ONE source identity (D-27.2/D-27.6). Both
earnings.live (faster-whisper small on-device, keyless/offline BYO-audio
— D-27.5) and earnings.hosted (fetch from EARNINGS_HOSTED_URL) produce
byte-identical rows from the SAME public call audio. The per-row source
overlay column is therefore always the shared identity "earnings_call" (so a
live row and a hosted row reconcile — no SourceMismatchError), while the
delivery column carries the channel lineage (live / hosted). This is
exactly the satellite noaa_goes precedent.
knowledge_time = transcript availability (post-call), NOT event_time. The
overlay knowledge_time is derived from each row’s transcript_available_at
(when the transcript was published), never the call air time — the PIT leakage
invariant (D-27.11) that keeps earnings facts backtest-safe. The PIT alignment +
leakage assertions themselves live in
mostlyright.markets.earnings.pit.
This adapter is a thin parser: it takes already-extracted satellite-payload or
local-file rows (it does NOT run faster-whisper here — that is the satellite’s
job; the live fetch path lazy-imports the STT engine guarded by the
[earnings] extra and raises an install hint if missing).
Module Attributes
Section titled “Module Attributes”EARNINGS_HOSTED_URL | Env-var name for the hosted earnings-feed seam (the CONSUMER side of the satellite serving layer — the serving layer itself is out of scope here). |
|---|---|
EARNINGS_LIVE_STREAM_SOURCE | The live delivery-channel source id (D-27.16, 27-12). |
EARNINGS_SOURCE_IDENTITY | The single shared source identity (D-27.2). |
Classes
Section titled “Classes”EarningsAdapter() | Thin earnings-feed adapter (live + hosted). |
|---|
mostlyright.weather.catalog.earnings.EARNINGS_HOSTED_URL = ‘EARNINGS_HOSTED_URL’
Section titled “mostlyright.weather.catalog.earnings.EARNINGS_HOSTED_URL = ‘EARNINGS_HOSTED_URL’”Env-var name for the hosted earnings-feed seam (the CONSUMER side of the satellite serving layer — the serving layer itself is out of scope here).
mostlyright.weather.catalog.earnings.EARNINGS_LIVE_STREAM_SOURCE = ‘earnings.hosted.stream’
Section titled “mostlyright.weather.catalog.earnings.EARNINGS_LIVE_STREAM_SOURCE = ‘earnings.hosted.stream’”The live delivery-channel source id (D-27.16, 27-12). Distinct from the
post-call earnings.hosted ledger: rows tagged this way are PROVISIONAL
and firewalled out of every backtest AND settlement read (see
mostlyright.markets.earnings.pit). It is a per-row overlay value, NOT
a registered adapter source — the live consumer is reached via
EarningsAdapter.stream(), never research() / the merge join.
mostlyright.weather.catalog.earnings.EARNINGS_SOURCE_IDENTITY = ‘earnings_call’
Section titled “mostlyright.weather.catalog.earnings.EARNINGS_SOURCE_IDENTITY = ‘earnings_call’”The single shared source identity (D-27.2). Live STT + the hosted feed are the SAME upstream public call audio, so both stamp this — they reconcile, they do not mismatch.
class mostlyright.weather.catalog.earnings.EarningsAdapter
Section titled “class mostlyright.weather.catalog.earnings.EarningsAdapter”Bases: object
Thin earnings-feed adapter (live + hosted).
SUPPORTED_SOURCES : ClassVar[list[str]] = [‘earnings.live’, ‘earnings.hosted’]
Section titled “SUPPORTED_SOURCES : ClassVar[list[str]] = [‘earnings.live’, ‘earnings.hosted’]”fetch(source, ticker, event_date, , client=None, retrieved_at=None)
Section titled “fetch(source, ticker, event_date, , client=None, retrieved_at=None)”Fetch earnings rows from source.
earnings.hosted (the DEFAULT / our-infra path, D-27.6) httpx-fetches
the served /facts feed at EARNINGS_HOSTED_URL, validates the
payload shape, then projects through from_rows() — producing rows
BYTE-IDENTICAL to the on-device earnings.live tier (same engine
deployed centrally; only the delivery overlay differs, the source
identity earnings_call is shared so live↔hosted reconcile).
earnings.live runs the on-device faster-whisper small STT path
(lazy-imported, guarded by the [earnings] extra) — the actual
capture/STT is the satellite engine’s job; the SDK live path here is the
keyless/offline BYO-audio seam, exercised via from_rows().
client injects an httpx.Client (tests pass a MockTransport);
retrieved_at overrides the overlay retrieval stamp (defaults to now).
Raises EarningsError when
EARNINGS_HOSTED_URL is unset (the seam is opt-in) or the fetch fails,
and SchemaValidationError when the
served payload is malformed (rejected BEFORE overlay-stamping).
- Return type:
DataFrame - Parameters:
static from_rows(rows, , source=‘earnings.hosted’, retrieved_at=None)
Section titled “static from_rows(rows, , source=‘earnings.hosted’, retrieved_at=None)”Project satellite-payload / local-file rows to a canonical DataFrame.
Emits the canonical schema.earnings_transcript.v1 /
schema.earnings_fact.v1 fields present on the input rows plus the
overlay columns source / retrieved_at / knowledge_time /
event_time and the delivery lineage column.
Rows are BYTE-IDENTICAL across earnings.live and earnings.hosted
(D-27.6); only delivery differs. source is always the shared
identity "earnings_call" so live↔hosted reconcile.
- Return type:
DataFrame - Parameters:
async stream(ticker, call_id, , base_url, token=None, headers=None, client=None)
Section titled “async stream(ticker, call_id, , base_url, token=None, headers=None, client=None)”Consume the live 27-11 SSE feed → incremental canonical rows. Async.
Mirrors the CWOP stream() async-generator precedent
(mostlyright.weather.cwop.stream()): an async for over this
yields incremental schema.earnings_transcript.v1 /
schema.earnings_fact.v1 rows as the call airs. Every row is tagged
source="earnings.hosted.stream" (EARNINGS_LIVE_STREAM_SOURCE)
and carries:
spoken_at— the aired event time (from the payload’sspoken_at/event_time);knowledge_time— the STT-finalization / publish wallclock (>= spoken_at, from the payload’spublished_at/knowledge_time; NEVERspoken_at— codex P2 / D-27.16);stream_seq— the SSEid:(monotonic; drives resume);is_final— STT-segment finality ONLY (never settlement authority);resolution_status—"provisional"for a counted fact delta.
The consumer is a pure pass-through for kalshi_counted — it reads it
straight from the fact-delta row and NEVER re-derives counts client-side
(fail-closed stays at the satellite). A resume_incomplete frame is
surfaced as a row with event="resume_incomplete" so a caller
reconciles from the ledger rather than silently gapping.
- Parameters:
- ticker (
str) – The issuer ticker (a query param on the/streamURL). - call_id (
str) – The call id (a query param on the/streamURL). - base_url (
str) – The/streamendpoint (the serving layer is the satellite + 27-08; the SDK ships no default). - token (
str|None) – A short-lived signed-URL token (the browserEventSourcepath cannot set a header; the server-sidehttpxreader here can, but the token is passed as a query param for wire parity). - headers (
Mapping[str,str] |None) – Extra request headers (e.g. anAuthorizationheader for the header-auth reader variant). - client (
object|None) – An optionalhttpx.AsyncClient(tests inject a mock transport). Passed straight toconsume_sse().
- ticker (
- Yields:
Canonical row dicts tagged
source="earnings.hosted.stream". - Return type:
AsyncIterator[dict[str,object]]