-- 053: Line 105 ranked multi-select taxonomy + category-specific metadata -- -- The 2026 FCC Form 499-A Line 105 is an explicit multi-select (ranked 1-5) -- across 22 carrier categories. Migration 038 stored `service_categories -- TEXT[]` and `filer_type TEXT` but the handler treated Line 105 as a -- single category. This migration replaces that with: -- -- line_105_primary — single required primary category id -- line_105_categories — JSONB array of {id, rank, infra_type, is_tdm_service} -- -- Reseller handling: local_reseller and toll_reseller are NOT standalone -- categories in our data model. A CLEC or IXC with `infra_type='reseller'` -- triggers the corresponding Line 105 box being ticked automatically by -- form_499a.py. Similarly an MVNO is wireless with infra_type='mvno'. -- -- Category-specific metadata lives in dedicated JSONB columns so we can -- evolve each without touching the shared table schema. -- ── Line 105 primary + ranked multi-select ────────────────────────────── ALTER TABLE telecom_entities ADD COLUMN IF NOT EXISTS line_105_primary TEXT; ALTER TABLE telecom_entities ADD COLUMN IF NOT EXISTS line_105_categories JSONB NOT NULL DEFAULT '[]'::jsonb; -- Example shape: -- [{"id":"clec","rank":1,"infra_type":"reseller","is_tdm_service":false}, -- {"id":"ixc", "rank":2,"infra_type":"facilities"}] -- -- GIN index for "find every filer that provides wireless service" etc. CREATE INDEX IF NOT EXISTS idx_telecom_entities_line_105_categories ON telecom_entities USING gin (line_105_categories jsonb_path_ops); CREATE INDEX IF NOT EXISTS idx_telecom_entities_line_105_primary ON telecom_entities(line_105_primary) WHERE line_105_primary IS NOT NULL; -- ── Category-specific metadata JSONB columns ──────────────────────────── -- wireless_meta shape: -- { spectrum_bands: ["Lower 700 MHz", "PCS 1900"], host_mno: null, -- post_paid_subs: 12000, pre_paid_subs: 3500, -- cell_site_count: 42, msa_coverage: ["MSA-001","MSA-003"] } ALTER TABLE telecom_entities ADD COLUMN IF NOT EXISTS wireless_meta JSONB; -- satellite_meta shape: -- { earth_station_license_ids: ["E123456"], orbital_slot: "W 73.0", -- satellite_operator: "Intelsat", service_type: "FSS", -- mss_us_subscribers: null } ALTER TABLE telecom_entities ADD COLUMN IF NOT EXISTS satellite_meta JSONB; -- audio_bridging_meta shape: -- { platform: "proprietary", toll_free_accessible: true, -- participant_min_revenue_cents: 1200000, -- subscription_revenue_cents: 4500000 } ALTER TABLE telecom_entities ADD COLUMN IF NOT EXISTS audio_bridging_meta JSONB; -- private_line_circuits: one row per circuit. -- [{id, bandwidth, endpoint_a:{city,state,country}, -- endpoint_b:{city,state,country}, monthly_revenue_cents}, ...] ALTER TABLE telecom_entities ADD COLUMN IF NOT EXISTS private_line_circuits JSONB; -- ── Backfill from the single-valued filer_type/service_categories ─────── -- Existing rows have filer_type populated (e.g., 'interconnected_voip', -- 'clec'). Seed line_105_primary + line_105_categories from it so we -- don't break live data. infra_type from 038 is also carried into the -- JSONB entry. UPDATE telecom_entities SET line_105_primary = filer_type, line_105_categories = jsonb_build_array( jsonb_build_object( 'id', filer_type, 'rank', 1, 'infra_type', COALESCE(infra_type, 'facilities'), 'is_tdm_service', false ) ) WHERE line_105_primary IS NULL AND filer_type IS NOT NULL;