Thales
← research journal

An internal research document, published verbatim by the automated daily export — not written for an audience, and better for it. All performance discussed is simulated paper trading; nothing here is investment advice.

DISMISSED — SKW-2 — the skew capture sends dash-class symbols Alpaca rejects; four names have never captured a row

status: dismissed by TRIAGE 2026-09-14 · OVERFLOW — ranked 18 of 21 at the pre-registered 12-item cap · raised 2026-09-04, grew 2026-09-06 (SKW-4 leg 3 re-routed here) · body verbatim below

Resolution — mechanical overflow; live and bleeding, but blocked on one owner ruling with no date and a 2027 consumer

research/queue/open/ held 21 files after this run's sweep against the pre-registered 12-item cap (ops/QUEUE_TRIAGE.md:86-91), so the nine lowest-ranked are dismissed with reopen conditions. This one is dismissed with the most reluctance in the set: it bleeds every capture day. It ranks here because its only consumer, B4 skew activation checkpoint 1, is 2027-06 (NORTHSTAR.md §6), and it is 100% blocked on an owner ruling that has no date on it.

Re-verified live at HEAD 340bc5f, verbatim:

  • options_skew.py:280 — client.get_option_chain(OptionChainRequest( underlying_symbol=symbol)), the raw internal symbol, unmapped.
  • The mapper exists and is used at every trading boundary: to_alpaca_symbol defined alpaca_broker.py:31, applied at :153, :199, :240, :410. The capture path is the one place it is not.
  • Data confirms zero rows in data/options_skew.jsonl for BRK-B, BF-B, GHC and NVR — all four are in data/universe.csv (:244, :633, :684, :847).
  • CAPTURES.md still carries no per-name coverage note for any of the four.
  • PR #152 touched this module (SKW-3 deadline + session filter) and did not go near symbology.

Why it is a queue row and not a one-line fix: changing what a pre-registered capture stream collects mid-accrual is an owner policy call — that is the whole reason it was filed rather than patched.

Reopen condition. Reopen on or before 2026-12-01 if the four names are still at zero rows — that is early enough that the B4 checkpoint-1 sensitivity arithmetic (2–4 names of ~900 against cross-name medians and row floors) can be done with the correction in hand rather than after. Reopen immediately if a fifth never-captured name appears in the per-name census, or the moment the owner rules on mid-accrual stream changes. The fix site and the four names are recorded above so nothing needs re-deriving.


Body as filed (verbatim, untouched)

SKW-2 — the skew capture sends dash-class symbols Alpaca rejects; BRK-B and BF-B have never captured

status: open · raised 2026-09-01 (owner session; observed daily in skew logs since at least 08-28, first flagged 2026-08-29) · class: capture-stream completeness — deliberately a queue row, not a stealth fix, because the remedy changes what a pre-registered stream collects · judgement: owner call · effort ~0.25 pd · horizon: every capture day adds two more permanent per-name notches


Plain-language summary. Every skew snapshot logs skew: BRK-B chain fetch failed: invalid underlying symbol: BRK-B (and the same for BF-B). Same root cause as EXQ-1 (2026-08-26): the internal canon is the dash form, Alpaca wants BRK.B. The trading path got a symbology map at the broker boundary; the capture path (options_skew.py) still sends the dash form, so the two class-share names in the 903-name universe fail their chain fetch daily and have NEVER contributed rows to options_skew.jsonl, options_chains/, or options_iv_term/.

Why this is not just "apply the fix"

The fix is one line (to_alpaca_symbol at the fetch, reverse-map on write — the helpers already exist in execution/alpaca_broker.py). But applying it CHANGES A PRE-REGISTERED CAPTURE STREAM mid-accrual: two names would begin appearing on the fix date, with a permanent pre-fix hole behind them. The moat doctrine treats stream semantics as registered, and the B4 skew activation pin computes cross-name medians and row floors over the stream — so the change must be:

  1. dated in CAPTURES.md (per-name coverage note: BRK-B/BF-B absent <stream start>→<fix date>, present after — a vendor-reject hole, not a collection change);
  2. checked against the B4 activation criteria for sensitivity (adding 2 of ~900 names to medians is almost certainly immaterial — say so with the arithmetic, don't assume it);
  3. applied to the capture path only (the trading boundary is already fixed).

Test design + kill criterion

Unit: a fake chain client asserting the wire symbol is BRK.B while the persisted row's underlying is BRK-B; revert the map → red. Live check: first post-fix capture day shows both names in the day's jsonl and chains parquet, and the daily chain fetch failed warnings disappear.

Explicitly out of scope

The per-name backfill of the pre-fix hole (no free historical source — the same reason the whole stream is forward-only).


Triage note — 2026-09-07 (annotation only; the body above is untouched)

Premise re-verified from the data, and the row GAINED scope this week. At HEAD e25f80b, src/thales/data/options_skew.py:280 still sends the internal dash canon straight to the wire (OptionChainRequest(underlying_symbol=symbol)), with no to_alpaca_symbol — the helper that exists and is applied at every trading boundary (alpaca_broker.py:31, used at :153, :199, :240, :410). Independently confirmed: zero rows for BRK-B/BF-B (or their dot forms) anywhere in data/options_skew.jsonl across the whole stream, while BRK-B is in the universe (data/universe.csv:684). Neither prerequisite has landed — CAPTURES.md still carries no per-name coverage note for either name.

New scope, not triage's doing: SKW-4's built record explicitly re-routes its own leg 3 — the per-name coverage census — into this row (research/queue/built/skw-4-non-session-rows-served-and-per-name-coverage.md:126-129), naming GHC and NVR at 0 of 62 capture days. So this row now owns four never-captured names, not two, and the CAPTURES.md dated note it asks for covers all of them. Effort is still ~0.25 pd; the census leg adds a little.