Files
investor-flow/docs/adr/0011-symbol-search-index.md
Investor Flow Build ac94acf9e3
CI / Test & Type-Check (push) Canceled after 0s
feat: dealer flow, mirror portfolio (M21), options convexity, FINRA short interest, alert producers, vendor gate
Snapshot of in-progress module work across multiple slices:

- Dealer Flow: dealerExposureEngine, dealerMapService, dealerMapExplain,
  dealerMapIntegrity, dealerMapReplay, dealerStudyEngine, hanStyleLevels
- Mirror Portfolio (M21): fundRepository, captureIngest, mirrorAlertProducers,
  fund holdings strip, live book, position capture ingest
- Options: BSM, NormalizedOptionSurface types, OptionsChainRouter,
  ConvexityGate, option legs panel
- Alert producers: vixLevel, rotation, thesis, unlock, portfolioRisk,
  mirror (fund_capture, fund_13f, mirror_diff)
- FINRA short interest adapter + queue integration
- SEC company tickers adapter + ingest (symbol search index seed)
- Vendor gate (rate-limit-first data plane, ADR-0009)
- CUSIP registry, reverse 13F refresh, stock float service
- LRU cache, portfolio backtest engine
- Frontend: dealer-flow, funds, journal, lab, monitor, plan, portfolio,
  reports, screener, strategies, theses, guided-start, exits, more pages
- Volume profile, workspace profile, visibility-aware poll
- ADRs 0010 (mirror math not advice), 0011 (symbol search index)
- VENDOR_INTEGRATIONS.md, END_USER_TEST.md
- .gitignore: exclude DBs, .DS_Store, local config, agent scratch
2026-08-10 13:36:26 -04:00

2.3 KiB

ADR-0011: Symbol Search Index — issuer CIK via SEC seed, hybrid add-resolve

Symbols lacked issuer identity and the app's only autocomplete corpus was the demand set (already-tracked symbols), making new-symbol discovery impossible. We decided: the symbols table gains an issuer CIK column, seeded from the SEC's company_tickers.json bulk file (~12k US tickers, overwritten in place daily) via a scheduled queue job; autocomplete resolves local-first against this table; adding an unmatched string is a soft-block ("not in the SEC registry — add anyway?") followed by background hydration through the existing adapter queue; and the symbol page surfaces a two-tier "who holds this" strip (tracked funds with weight, then institution count). A symbol carries TWO CIK roles in this app — the issuer CIK (the company the ticker represents, on symbols) and the filer CIK (the fund that files 13Fs, on tracked_funds) — same identifier space, different edges.

Status: accepted (2026-07-28, grilling session).

Considered Options

  • Live yfinance search suggestions on keystroke — rejected: violates ADR-0009 (no live vendor call on the request path); rate limits make autocomplete unreliable.
  • Curated universe seed (S&P 500 / NASDAQ 100) — rejected: narrow, and carries no issuer CIKs.
  • Strict resolve (block unknown symbols) — rejected: users need fresh/post-file-update tickers; strictness is a question, not a wall.
  • Loose add (no confirmation) — rejected: silently accepting typos/delisted names pollutes the "known database" the autocomplete relies on.
  • Full-row upsert on daily seed — rejected: would clobber yfinance-hydrated ticker_kind (gates module applicability), sector, industry, peers; merge policy is column-scoped instead.

Consequences

  • Two ownership domains on symbols: SEC fills issuer identity (cik, name, exchange); yfinance hydration owns classification (ticker_kind, sector, industry, peers). No overwrite war.
  • Non-SEC rows (crypto, some ETFs, indexes) are never purged — the SEC universe is a subset, not the whole.
  • The daily seed makes the local index essentially complete for US equities, so live-search fallback is rarely needed.
  • Autocomplete correctness now depends on the scheduled materializer running; a missed day only delays new tickers by one day (stale-while-revalidate).