Skip to content

data_updater_v2.issues

issues.py — the pieces every section’s issues are made of: one observation, its identity, and the counts a monitoring receipt carries. Pure: the DataClient reads the tables and makes the observations (universe_issues …), writes them (observe_issues) and records the counts (record); the jobs decide when.

An observation is one mapping in the issue table’s words (tables/issues.py):

section the DataClient section (universe, daily ...)
issue_type what it is
severity warning or error
table_name the table it concerns
listing_id our listing id · global_id · symbol: who it concerns (None when nobody of ours)
target_key the rest of its identity ({"date": ...})
action the DataClient work that follows it (None: nothing to run)
source the vendor it concerns, when one
evidence what was seen (never part of the identity)

Its identity (issue_key) is the section, the kind, the table, who and the rest of the key: seen again, the issue is the same one.

Functions

assessment_key

assessment_key(obs: Mapping[str, Any]) -> str

The identity a verdict on an observation’s target is kept under (no issue type).

fetch_failures

fetch_failures(section: str, table_name: str, gaps: Mapping[str, Mapping[str, Any]], rows: Iterable[Any] = ()) -> list[dict[str, Any]]

The listings a build’s or an update’s fetch left unanswered (its gaps’ failed and error), as observations for observe_issues — what no table can show afterwards:

no_source no source carries the listing ("no source carries it"): no action
(a person, or the cleanup job through ``write_universe``'s ``fetch``)
fetch_failed no source answered (error) — retry
source_failed a source did not answer while another did: the record stands on the
others, a retry completes it — retry

rows: the catalog rows the run was handed (they name who by our ids); a symbol not among them is named by its symbol.

gap_findings

gap_findings(gaps: Mapping[str, Mapping[str, Any]]) -> list[dict[str, Any]]

The counts a build’s or an update’s monitoring receipt carries from its gaps (gaps.daily_bar_gaps … with failed): each key, how many listings it names — error, empty and failed as errors, the rest warnings; owed and days (counts and per-day logs) are no findings.

issue_key

issue_key(obs: Mapping[str, Any]) -> str

An observation’s identity: the same issue seen again has the same key.

observation

observation(section: str, issue_type: str, table_name: str, severity: str = 'warning', row: Any = None, symbol: str | None = None, target_key: Mapping[str, Any] | None = None, action: str | None = None, source: str | None = None, evidence: Mapping[str, Any] | None = None, listing_id: str | None = None, global_id: str | None = None) -> dict[str, Any]

One observation; row (a catalog row) names who by our ids, else listing_id / global_id / symbol as given.

split_change_observations

split_change_observations(changes: Iterable[Mapping[str, Any]], table_name: str) -> list[dict[str, Any]]

What a fetch changed against the stored splits (events.split_changes), as observations for observe_issues: split_changed per listing and day — action rebuild_prices: the daily (and, in the job’s intraday set, the minutes) up to that day rebuilt with the corrected splits. An announced change (a split not yet traded) asks nothing: no stored price leans on it yet.

universe_findings

universe_findings(issues: Sequence[Mapping[str, Any]]) -> list[dict[str, Any]]

The counts a section’s monitoring receipt carries: each issue type observed, by severity (common-dagster’s finding_summary: grouped, never one row per ticker).