-- Migration 039: Hype Cycle Analysis table -- Norton-Bass diffusion model output + Gartner phase classification per technology -- -- Computed by: packages/scraper/src/utils/hype-cycle-engine.ts -- Triggered: compute:hype-cycle job (daily 04:00) -- Extend market_metrics CHECK constraint to allow asp_decline_rate (already exists) + hype_score ALTER TABLE market_metrics DROP CONSTRAINT IF EXISTS market_metrics_metric_type_check; ALTER TABLE market_metrics ADD CONSTRAINT market_metrics_metric_type_check CHECK (metric_type = ANY (ARRAY[ 'vendor_count', 'shipment_share', 'asp_decline_rate', 'media_hype_index', 'patent_filings', 'port_shipments', 'revenue_usd', 'asp_usd', 'hype_score' -- 0-100 composite hype position on Gartner curve ])); -- Norton-Bass fitted parameters + phase classification (one row per technology per run) CREATE TABLE IF NOT EXISTS hype_cycle_analysis ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), computed_at timestamptz NOT NULL DEFAULT NOW(), technology text NOT NULL, -- e.g. '400G-QSFP-DD', '800G-OSFP' -- Bass model parameters (fitted) bass_p numeric, -- coefficient of innovation (0.001–0.03) bass_q numeric, -- coefficient of imitation (0.1–0.5) bass_m numeric, -- market potential (0.0–1.0 as share) -- Adoption curve metrics t_peak_year numeric, -- calendar year of peak adoption rate current_t numeric, -- years since first commercial availability current_share numeric, -- current shipment share (0–1) projected_share_1y numeric, -- projected share in 1 year projected_share_3y numeric, -- projected share in 3 years -- Hype Cycle positioning hype_phase text NOT NULL, -- see CHECK below hype_score numeric, -- 0-100: position on Gartner curve phase_since_year numeric, -- calendar year current phase started years_to_next_phase numeric, -- estimated years until next phase -- Price trajectory asp_current_usd numeric, -- current OEM ASP in USD asp_decline_pct_3y numeric, -- projected ASP decline % over 3 years -- Fit quality r_squared numeric, -- goodness of fit (0–1) data_points integer, -- number of historical data points used notes text, CONSTRAINT hype_cycle_phase_check CHECK (hype_phase = ANY (ARRAY[ 'innovation_trigger', 'peak_inflated_expectations', 'trough_disillusionment', 'slope_enlightenment', 'plateau_productivity' ])) ); CREATE INDEX IF NOT EXISTS idx_hype_tech_time ON hype_cycle_analysis (technology, computed_at DESC); -- Keep only the latest 90 days of analysis rows (historical snapshots for trend) CREATE OR REPLACE FUNCTION cleanup_hype_cycle_analysis() RETURNS void LANGUAGE sql AS $$ DELETE FROM hype_cycle_analysis WHERE computed_at < NOW() - INTERVAL '90 days'; $$;