{
  "schema_version": 1,
  "groups": {
    "identity": "Who the row is: ticker, listing and classification.",
    "price_volume": "Latest close, traded value, market cap and distance from key price levels.",
    "performance": "Percent price changes, and percentile ranks of those changes.",
    "relative_strength": "RS ratings within the market, RS line signals, beta and beta-adjusted RS.",
    "trend": "Weinstein stage, moving-average alignment and momentum flags.",
    "fundamentals": "Earnings and sales growth, with the comparison behind them.",
    "scores": "Screener scores and labels. Labels are screening output, not recommendations.",
    "vcp": "Volatility contraction pattern detector output.",
    "setup_engine": "Chart pattern detection, pivot, tightness and breakout readiness.",
    "opportunity": "Correction-survivor policy: gates, resilience score and action state.",
    "data_quality": "How much data a row had, why fields are null, and scan bookkeeping."
  },
  "fields": {
    "symbol": {"group": "identity", "type": "text", "unit": "label", "meaning": "Ticker as listed in this market, e.g. NVDA, 7203.T."},
    "company_name": {"group": "identity", "type": "text", "unit": "label", "meaning": "Company name from the stock universe."},
    "listing_search": {"group": "identity", "type": "text", "unit": "label", "meaning": "Symbol and company name joined, for text-search rules.", "note": "A filter-rule name the evaluator computes, not a row field. run_screen filters reject it.", "internal": true},
    "market": {"group": "identity", "type": "text", "unit": "label", "meaning": "Market code, e.g. US, JP, MY."},
    "exchange": {"group": "identity", "type": "text", "unit": "label", "meaning": "Listing exchange code, e.g. XNYS, XTKS."},
    "currency": {"group": "identity", "type": "text", "unit": "label", "meaning": "Listing currency; every local_currency field on the row uses it."},
    "ipo_date": {"group": "identity", "type": "date", "unit": "date", "meaning": "First trading date from fundamentals, else the first stored price bar.", "note": "A provider floor date or the first stored bar can stand in for it in any market, so do not quote it as a listing date. ipo_score reads the same date for its age points."},
    "ibd_industry_group": {"group": "identity", "type": "text", "unit": "label", "meaning": "IBD-style industry group name."},
    "ibd_group_rank": {"group": "identity", "type": "integer", "unit": "rank", "meaning": "Group's rank by the average RS of its stocks in this market; 1 is strongest.", "note": "Computed by this project, not published by IBD. Ranks compare within one market only."},
    "ibd_group_rank_date": {"group": "identity", "type": "date", "unit": "date", "meaning": "Date the group rank was calculated for."},
    "gics_sector": {"group": "identity", "type": "text", "unit": "label", "meaning": "Sector label from the data provider or the market taxonomy.", "note": "Not official GICS. Label sets differ by market, e.g. US Financial, JP Financial Services."},
    "gics_industry": {"group": "identity", "type": "text", "unit": "label", "meaning": "Industry label from the data provider or the market taxonomy.", "note": "Not official GICS. Label sets differ by market."},
    "market_themes": {"group": "identity", "type": "list", "unit": "label", "meaning": "Theme tags from the market taxonomy.", "note": "A list, so run_screen filters cannot test its tags."},

    "current_price": {"group": "price_volume", "type": "number", "unit": "local_currency", "meaning": "Latest daily close in the listing currency.", "note": "This bar can be newer or older than the result's as_of_date. Its date is opportunity_state.as_of_date."},
    "price": {"group": "price_volume", "type": "number", "unit": "local_currency", "meaning": "Name screen rules use for current_price.", "alias_of": "current_price"},
    "volume": {"group": "price_volume", "type": "number", "unit": "local_currency", "meaning": "Average daily traded value: average daily shares times the latest close.", "note": "Money, not a share count, in the listing currency. The share average has no single window: Yahoo's averageVolume in the US, a 50-session mean elsewhere, both at the latest fundamentals refresh. It can differ widely from adv_usd, so look at both on a name before quoting liquidity."},
    "listing_aware_volume": {"group": "price_volume", "type": "number", "unit": "local_currency", "meaning": "volume, except listing_only rows count as infinite so they pass liquidity minimums.", "note": "A filter-rule name the evaluator computes, not a row field. run_screen filters reject it.", "internal": true},
    "adv_usd": {"group": "price_volume", "type": "number", "unit": "usd", "meaning": "Average daily traded value in USD at the latest fundamentals refresh.", "note": "Prices the shares at market cap divided by shares outstanding, not the latest close, so it can differ widely from volume even for a US stock, and it can be 0. Look at both on a name before quoting liquidity."},
    "market_cap": {"group": "price_volume", "type": "number", "unit": "local_currency", "meaning": "Market capitalisation in the listing currency, as of the latest fundamentals refresh.", "note": "Not recomputed from the latest close. Can be 0."},
    "market_cap_usd": {"group": "price_volume", "type": "number", "unit": "usd", "meaning": "market_cap in USD at the FX rate of the latest fundamentals refresh."},
    "adr_percent": {"group": "price_volume", "type": "number", "unit": "percent", "meaning": "Mean of (high - low) / close over the last 20 sessions."},
    "gap_percent": {"group": "price_volume", "type": "number", "unit": "percent", "meaning": "Latest open versus the prior close; positive is a gap up."},
    "volume_surge": {"group": "price_volume", "type": "number", "unit": "ratio", "meaning": "Latest session's shares divided by the prior 50 sessions' average; 1 is normal."},
    "week_52_high_distance": {"group": "price_volume", "type": "number", "unit": "percent", "meaning": "Percent below the 52-week closing high; 0 is at the high.", "range": [0, 100]},
    "week_52_low_distance": {"group": "price_volume", "type": "number", "unit": "percent", "meaning": "Percent above the 52-week closing low; 0 is at the low."},
    "ema_10_distance": {"group": "price_volume", "type": "number", "unit": "percent", "meaning": "Percent above (+) or below (-) the 10-day EMA of closes."},
    "ema_20_distance": {"group": "price_volume", "type": "number", "unit": "percent", "meaning": "Percent above (+) or below (-) the 20-day EMA of closes."},
    "ema_50_distance": {"group": "price_volume", "type": "number", "unit": "percent", "meaning": "Percent above (+) or below (-) the 50-day EMA of closes."},

    "price_change_1d": {"group": "performance", "type": "number", "unit": "percent", "meaning": "Percent change from the prior close to the latest close."},
    "perf_week": {"group": "performance", "type": "number", "unit": "percent", "meaning": "Percent change in the close over 5 sessions."},
    "perf_month": {"group": "performance", "type": "number", "unit": "percent", "meaning": "Percent change in the close over 21 sessions."},
    "perf_3m": {"group": "performance", "type": "number", "unit": "percent", "meaning": "Percent change in the close over 67 sessions."},
    "perf_6m": {"group": "performance", "type": "number", "unit": "percent", "meaning": "Percent change in the close over 126 sessions."},
    "pct_day": {"group": "performance", "type": "number", "unit": "percentile", "meaning": "Percentile rank of price_change_1d among this market's rows; 100 is the biggest gain.", "range": [0, 100], "note": "A rank, not a percent change. Quote price_change_1d for the move."},
    "pct_week": {"group": "performance", "type": "number", "unit": "percentile", "meaning": "Percentile rank of perf_week among this market's rows; 100 is the biggest gain.", "range": [0, 100], "note": "A rank, not a percent change. Quote perf_week for the move."},
    "pct_month": {"group": "performance", "type": "number", "unit": "percentile", "meaning": "Percentile rank of perf_month among this market's rows; 100 is the biggest gain.", "range": [0, 100], "note": "A rank, not a percent change. Quote perf_month for the move."},
    "price_trend": {"group": "performance", "type": "integer", "unit": "label", "meaning": "30-session direction: 1 up over 0.5%, -1 down over 0.5%, 0 flat.", "range": [-1, 1]},
    "price_sparkline_data": {"group": "performance", "type": "list", "unit": "ratio", "meaning": "Last 30 closes, scaled so the first is 1.0.", "note": "In the published JSON only. The MCP tools drop it, so describe_fields reports rows_with_value as null."},

    "rs_rating": {"group": "relative_strength", "type": "number", "unit": "percentile", "meaning": "Overall relative strength within this market; 99 is strongest, 1 weakest.", "range": [1, 99], "note": "Rated rows are in the market's RS universe, set by the StockUniverse.is_common_stock flag, and have an adjusted close at every anchor back 252 sessions. Anything else is null, which is not a weak rating. Some markets' universes include ETFs, so percentiles there are not stock-only. Not comparable across markets."},
    "rs_rating_1m": {"group": "relative_strength", "type": "number", "unit": "percentile", "meaning": "Relative strength over 21 sessions within this market; 99 is strongest.", "range": [1, 99], "note": "Young listings can have this without rs_rating."},
    "rs_rating_3m": {"group": "relative_strength", "type": "number", "unit": "percentile", "meaning": "Relative strength over 63 sessions within this market; 99 is strongest.", "range": [1, 99], "note": "Young listings can have this without rs_rating."},
    "rs_rating_12m": {"group": "relative_strength", "type": "number", "unit": "percentile", "meaning": "Relative strength over 252 sessions within this market; 99 is strongest.", "range": [1, 99]},
    "rs_as_of_date": {"group": "relative_strength", "type": "date", "unit": "date", "meaning": "Trading day the RS ratings were calculated for."},
    "beta": {"group": "relative_strength", "type": "number", "unit": "ratio", "meaning": "Beta of daily returns against the market's benchmark over up to 252 sessions.", "range": [-5, 10], "note": "Null below 200 sessions, or when the result falls outside the range."},
    "beta_adj_rs": {"group": "relative_strength", "type": "number", "unit": "score", "meaning": "rs_rating divided by beta, with beta floored at 0.5 and the result capped at 100.", "range": [0, 100], "note": "Not a 1-99 percentile. Rows can tie at the cap."},
    "beta_adj_rs_1m": {"group": "relative_strength", "type": "number", "unit": "score", "meaning": "rs_rating_1m divided by beta, with beta floored at 0.5 and the result capped at 100.", "range": [0, 100]},
    "beta_adj_rs_3m": {"group": "relative_strength", "type": "number", "unit": "score", "meaning": "rs_rating_3m divided by beta, with beta floored at 0.5 and the result capped at 100.", "range": [0, 100]},
    "beta_adj_rs_12m": {"group": "relative_strength", "type": "number", "unit": "score", "meaning": "rs_rating_12m divided by beta, with beta floored at 0.5 and the result capped at 100.", "range": [0, 100]},
    "rs_line_new_high": {"group": "relative_strength", "type": "boolean", "unit": "flag", "meaning": "Stock-to-benchmark ratio at a 252-session high on the latest session.", "note": "False also when benchmark data is missing, not only when the check failed. On a short history the window is whatever bars exist, so check history_bars."},
    "rs_line_new_high_before_price": {"group": "relative_strength", "type": "boolean", "unit": "flag", "meaning": "Blue dot on the latest session: RS line at a 252-session high while price is not.", "note": "On a short history the window is whatever bars exist, so check history_bars."},
    "rs_line_blue_dot_recent": {"group": "relative_strength", "type": "boolean", "unit": "flag", "meaning": "A blue dot fired on any of the last 5 sessions.", "note": "On a short history the window is whatever bars exist, so check history_bars."},
    "rs_line_new_high_date": {"group": "relative_strength", "type": "date", "unit": "date", "meaning": "Latest date the RS line made a 252-session high.", "note": "On a short history the window is whatever bars exist, so check history_bars."},
    "rs_sparkline_data": {"group": "relative_strength", "type": "list", "unit": "ratio", "meaning": "Last 30 stock-to-benchmark ratios, scaled so the first is 1.0.", "note": "In the published JSON only. The MCP tools drop it, so describe_fields reports rows_with_value as null."},
    "rs_trend": {"group": "relative_strength", "type": "integer", "unit": "label", "meaning": "Slope of the 30-session RS ratio: 1 improving, -1 declining, 0 flat.", "range": [-1, 1]},

    "stage": {"group": "trend", "type": "integer", "unit": "label", "meaning": "Weinstein stage: 1 basing, 2 advancing, 3 topping, 4 declining.", "range": [1, 4]},
    "stage_name": {"group": "trend", "type": "text", "unit": "label", "meaning": "Name of the stage: Basing, Advancing, Topping or Declining."},
    "ma_alignment": {"group": "trend", "type": "boolean", "unit": "flag", "meaning": "Close above the 50-day SMA, 50 above 150, 150 above 200, and the 200-day up 1% over a month."},
    "pocket_pivot": {"group": "trend", "type": "boolean", "unit": "flag", "meaning": "Up day on more volume than any down day of the prior 10 sessions, at or above the 50-day SMA."},
    "power_trend": {"group": "trend", "type": "boolean", "unit": "flag", "meaning": "Close above the 21-day EMA, EMA above a rising 50-day SMA, and 10 straight closes above the EMA."},

    "eps_growth_qq": {"group": "fundamentals", "type": "number", "unit": "percent", "meaning": "EPS growth for the latest reported period, against the comparison in growth_metric_basis.", "note": "growth_metric_basis on the row is the only authority for the comparison. quarterly_qoq compares with the prior quarter, comparable_period_yoy with the same period a year earlier. Uncapped, so extreme values occur."},
    "eps_growth_yy": {"group": "fundamentals", "type": "number", "unit": "percent", "meaning": "EPS growth over a year: the latest period against the same period a year earlier.", "note": "Uncapped, so extreme values occur."},
    "sales_growth_qq": {"group": "fundamentals", "type": "number", "unit": "percent", "meaning": "Sales growth for the latest reported period, against the comparison in growth_metric_basis.", "note": "Read growth_metric_basis on the row, as for eps_growth_qq. Uncapped."},
    "sales_growth_yy": {"group": "fundamentals", "type": "number", "unit": "percent", "meaning": "Sales growth over a year: the latest period against the same period a year earlier.", "note": "Uncapped."},
    "growth_metric_basis": {"group": "fundamentals", "type": "text", "unit": "label", "meaning": "Comparison behind eps_growth_qq and sales_growth_qq: quarterly_qoq, comparable_period_yoy or unavailable.", "note": "Set from the gap between the two latest statements. A quarter-sized gap gives quarterly_qoq. Any other gap gives comparable_period_yoy in HK and JP, and unavailable elsewhere. Fewer than two statements give unavailable. A row can hold a growth value with basis unavailable, and its comparison is then unknown."},
    "growth_reporting_cadence": {"group": "fundamentals", "type": "text", "unit": "label", "meaning": "Cadence inferred from statement dates: quarterly, semiannual, annual, unknown or insufficient_history."},
    "eps_rating": {"group": "fundamentals", "type": "integer", "unit": "percentile", "meaning": "EPS percentile rank from the fundamentals store; 99 is strongest.", "range": [0, 99], "note": "Read rows_with_value in describe_fields before relying on it."},
    "peg_ratio": {"group": "fundamentals", "type": "number", "unit": "ratio", "meaning": "Price/earnings-to-growth ratio.", "note": "The scan does not copy it from fundamentals to the row. Read rows_with_value in describe_fields before relying on it."},

    "composite_score": {"group": "scores", "type": "number", "unit": "score", "meaning": "Equal-weight average of the screener scores that ran, plus any ipo_bonus.", "range": [0, 100]},
    "composite_reason": {"group": "scores", "type": "text", "unit": "label", "meaning": "Why the composite was adjusted: ipo_uplift, else null."},
    "rating": {"group": "scores", "type": "text", "unit": "label", "meaning": "Overall label from composite_score and screener passes: Strong Buy, Buy, Watch, Pass, Insufficient Data or Error.", "note": "A screening label, not a recommendation."},
    "minervini_score": {"group": "scores", "type": "number", "unit": "score", "meaning": "Minervini template score from RS, stage, MA alignment, 52-week position and VCP; higher is better.", "range": [0, 100]},
    "minervini_rating": {"group": "scores", "type": "text", "unit": "label", "meaning": "Minervini label: Strong Buy, Buy, Watch or Pass."},
    "passes_template": {"group": "scores", "type": "boolean", "unit": "flag", "meaning": "minervini_score at least 70, rs_rating at least 70 and stage 2."},
    "canslim_score": {"group": "scores", "type": "number", "unit": "score", "meaning": "CANSLIM score from earnings, new highs, volume, RS and institutional ownership; higher is better.", "range": [0, 100]},
    "canslim_rating": {"group": "scores", "type": "text", "unit": "label", "meaning": "CANSLIM label: Strong Buy, Buy, Watch or Pass."},
    "ipo_score": {"group": "scores", "type": "number", "unit": "score", "meaning": "IPO score from age, gain since listing, stability, volume and revenue growth.", "range": [0, 100], "note": "Computed for seasoned stocks too, so a value does not mean a recent IPO. Its age points read ipo_date, which can be a provider floor date or the first stored bar, so a seasoned name can score high."},
    "ipo_bonus": {"group": "scores", "type": "number", "unit": "score", "meaning": "Points added to composite_score for a strong ipo_score with under 252 bars of history.", "range": [0, 15]},
    "custom_score": {"group": "scores", "type": "number", "unit": "score", "meaning": "Percent of points earned on the default custom filters: price, RS, liquidity, market cap, growth, MA alignment.", "range": [0, 100], "note": "Its price band is in local currency, so scores are not comparable across markets."},
    "volume_breakthrough_score": {"group": "scores", "type": "number", "unit": "score", "meaning": "Record-volume score: a 5-year, 1-year or since-IPO volume high in the last 5 sessions, decayed by age.", "range": [0, 100], "note": "0 means no record found."},
    "volume_breakthrough_rating": {"group": "scores", "type": "text", "unit": "label", "meaning": "Label from how many record-volume checks hit: Strong Buy, Buy, Watch or Pass."},

    "vcp_detected": {"group": "vcp", "type": "boolean", "unit": "flag", "meaning": "vcp_score at least 65, with contracting pullbacks and price tight near recent highs."},
    "vcp_score": {"group": "vcp", "type": "number", "unit": "score", "meaning": "Score from pullback depth, volume, tightness and ATR contraction; 0 with too few bases.", "range": [0, 100]},
    "vcp_num_bases": {"group": "vcp", "type": "integer", "unit": "count", "meaning": "Consolidation bases the VCP detector found."},
    "vcp_pivot": {"group": "vcp", "type": "number", "unit": "local_currency", "meaning": "Highest closing-price peak of the last two bases, in the listing currency.", "note": "The detector sees only closes, so this is not an intraday high."},
    "vcp_ready_for_breakout": {"group": "vcp", "type": "boolean", "unit": "flag", "meaning": "(vcp_pivot - close) / close is at most 3%.", "note": "Also true when price is already far above the pivot."},
    "vcp_contraction_ratio": {"group": "vcp", "type": "number", "unit": "ratio", "meaning": "Share of successive pullbacks shallower than the one before; 1 means all of them.", "range": [0, 1], "note": "0 can mean it was never calculated, because a row with fewer than three bases gets 0. Check vcp_num_bases."},
    "vcp_atr_score": {"group": "vcp", "type": "number", "unit": "score", "meaning": "Contraction score from a close-to-close volatility proxy: the 14-session mean absolute change in the close, recent against about 30 sessions ago; higher is tighter.", "range": [0, 100], "note": "Not true range, because the detector sees only closes."},

    "se_setup_score": {"group": "setup_engine", "type": "number", "unit": "score", "meaning": "60% se_quality_score plus 40% se_readiness_score.", "range": [0, 100], "note": "It does not read the stock's stage, so declining stocks can score high. A score alone is not a setup."},
    "se_quality_score": {"group": "setup_engine", "type": "number", "unit": "score", "meaning": "Quality of the primary detected pattern; higher is better.", "range": [0, 100]},
    "se_readiness_score": {"group": "setup_engine", "type": "number", "unit": "score", "meaning": "Breakout readiness of the primary detected pattern; higher is better.", "range": [0, 100]},
    "se_setup_ready": {"group": "setup_engine", "type": "boolean", "unit": "flag", "meaning": "True only when no check failed, across every detector and every setup gate: scores, early zone, ATR, volume dry-up, RS and trend context.", "note": "A detector that found nothing counts as a failed check, so a false does not say a stock failed a setup gate. true_rows in describe_fields counts the true rows in this publish and does not say why a row is false."},
    "se_pattern_primary": {"group": "setup_engine", "type": "text", "unit": "label", "meaning": "Best detected pattern, e.g. cup_with_handle, three_weeks_tight, high_tight_flag, nr7_inside_day.", "note": "The best candidate is named even below the confidence floor, so a name alone is not a setup. A preset match means only that its rules passed, so check stage, se_in_early_zone, se_pivot_date and action_state before calling it a setup."},
    "se_pattern_confidence": {"group": "setup_engine", "type": "number", "unit": "score", "meaning": "Detector confidence in the primary pattern; 100 is highest.", "range": [0, 100], "note": "It does not read the stock's stage, so declining stocks can score high. A score alone is not a setup."},
    "se_pivot_price": {"group": "setup_engine", "type": "number", "unit": "local_currency", "meaning": "Breakout level of the primary pattern, in the listing currency.", "note": "The pivot can be years old, so check se_pivot_date."},
    "se_pivot_type": {"group": "setup_engine", "type": "text", "unit": "label", "meaning": "What the pivot level is, e.g. handle_high, flag_high, tight_area_high."},
    "se_pivot_date": {"group": "setup_engine", "type": "date", "unit": "date", "meaning": "Date of the pivot level."},
    "se_distance_to_pivot_pct": {"group": "setup_engine", "type": "number", "unit": "percent", "meaning": "Close against the pivot: positive above it, negative below it.", "note": "The pivot can be years old, so check se_pivot_date."},
    "se_in_early_zone": {"group": "setup_engine", "type": "boolean", "unit": "flag", "meaning": "Close from 2% below to 3% above the pivot.", "note": "The pivot can be years old, so check se_pivot_date."},
    "se_extended_from_pivot": {"group": "setup_engine", "type": "boolean", "unit": "flag", "meaning": "Close more than 10% above the pivot."},
    "se_base_length_weeks": {"group": "setup_engine", "type": "number", "unit": "weeks", "meaning": "Length of the primary pattern's base."},
    "se_base_depth_pct": {"group": "setup_engine", "type": "number", "unit": "percent", "meaning": "Depth or width of the base; what it measures depends on the pattern.", "note": "Cup depth, flag depth, tight-range width or distance from high. Can exceed 100 on three_weeks_tight rows, so it is not always a drawdown."},
    "se_support_tests_count": {"group": "setup_engine", "type": "number", "unit": "count", "meaning": "Support tests within the base.", "note": "Only rows whose primary pattern is first_pullback have it."},
    "se_tight_closes_count": {"group": "setup_engine", "type": "number", "unit": "count", "meaning": "Weeks in a three-weeks-tight run.", "note": "Only three_weeks_tight rows have it."},
    "se_atr14_pct": {"group": "setup_engine", "type": "number", "unit": "percent", "meaning": "14-session Wilder ATR as a percent of the close."},
    "se_bb_width_pctile_252": {"group": "setup_engine", "type": "number", "unit": "percentile", "meaning": "Percentile of Bollinger width within the stock's own last 252 sessions; low is tight.", "range": [0, 100]},
    "se_bb_squeeze": {"group": "setup_engine", "type": "boolean", "unit": "flag", "meaning": "se_bb_width_pctile_252 at or below 20."},
    "se_volume_vs_50d": {"group": "setup_engine", "type": "number", "unit": "ratio", "meaning": "Latest shares divided by a 50-session average that includes the latest session."},
    "se_up_down_volume_ratio_10d": {"group": "setup_engine", "type": "number", "unit": "ratio", "meaning": "Up-day volume over down-day volume across 10 sessions; above 1 means more up volume.", "note": "The denominator floors at 1e-9, so 10 sessions without a down day give huge values. Use medians."},
    "se_quiet_days_10d": {"group": "setup_engine", "type": "number", "unit": "count", "meaning": "Sessions of the last 10 with volume under 80% of its 50-session average and range under ATR.", "range": [0, 10]},
    "se_rs_line_new_high": {"group": "setup_engine", "type": "boolean", "unit": "flag", "meaning": "RS line at a 252-session high on the latest session, as the setup engine sees it.", "note": "On a short history the window is whatever bars exist, so check history_bars."},
    "se_rs_line_blue_dot": {"group": "setup_engine", "type": "boolean", "unit": "flag", "meaning": "RS line at a 252-session high on the latest session while price is not.", "note": "On a short history the window is whatever bars exist, so check history_bars."},
    "se_timeframe": {"group": "setup_engine", "type": "text", "unit": "label", "meaning": "Payload label that defaults to daily, whatever bars the pattern used.", "note": "It does not give the pattern's timeframe. three_weeks_tight and cup_with_handle use weekly bars."},

    "correction_survivor": {"group": "opportunity", "type": "boolean", "unit": "flag", "meaning": "Passes the leadership, trend, structure, liquidity and freshness gates, with all required evidence.", "note": "False when a gate failed and also when evidence is missing. failed_checks in opportunity_state names which for a row. true_rows in describe_fields counts the true rows in this publish and does not say why a row is false."},
    "resilience_score": {"group": "opportunity", "type": "number", "unit": "score", "meaning": "Sum of the five 0-20 pillars in opportunity_state's score_pillars.", "range": [0, 100], "note": "Null unless every input is known, and se_tight_closes_count exists only on three_weeks_tight rows, so rows with any other primary pattern are null."},
    "action_state": {"group": "opportunity", "type": "text", "unit": "label", "meaning": "Policy state, first match wins: exit_risk, event_risk, extended, data_limited, then setup_ready or watch.", "note": "A policy label, not advice. exit_risk means a hard flag: the close is below the 50-day SMA. data_limited is usually a data gap, not a verdict on the stock. setup_ready needs correction_survivor, se_setup_ready and se_in_early_zone together, so its absence from describe_fields values says nothing about the stocks."},
    "opportunity_state": {"group": "opportunity", "type": "object", "unit": "none", "meaning": "Evidence behind action_state: gates passed and failed, score pillars, metrics and data availability.", "note": "Its as_of_date is the row's last price bar, which can differ from the scan's as_of_date."},

    "is_scannable": {"group": "data_quality", "type": "boolean", "unit": "flag", "meaning": "False when no screener could score the row: too little history, or no RS rating."},
    "history_bars": {"group": "data_quality", "type": "integer", "unit": "count", "meaning": "Daily price bars available to the scan."},
    "field_availability": {"group": "data_quality", "type": "object", "unit": "none", "meaning": "Why fields are null: status and reason_code per field, for ownership, short interest and growth.", "note": "In the published JSON only. The MCP tools drop it, so describe_fields reports rows_with_value as null."},
    "data_status": {"group": "data_quality", "type": "text", "unit": "label", "meaning": "Scan outcome: complete, insufficient_history or error.", "internal": true},
    "scan_mode": {"group": "data_quality", "type": "text", "unit": "label", "meaning": "History tier: full at 252+ bars, ipo_weighted at 30-251, listing_only below 30.", "internal": true},
    "screeners_run": {"group": "data_quality", "type": "list", "unit": "label", "meaning": "Screeners that scored this row.", "internal": true},
    "applicable_screeners": {"group": "data_quality", "type": "list", "unit": "label", "meaning": "Screeners this row had enough data for.", "internal": true},
    "unavailable_screeners": {"group": "data_quality", "type": "list", "unit": "label", "meaning": "Screeners this row did not have enough data for.", "internal": true},
    "matched_groups": {"group": "data_quality", "type": "list", "unit": "none", "meaning": "Setup groups matched by a query's filter expression.", "internal": true},
    "rs_formula_version": {"group": "data_quality", "type": "text", "unit": "label", "meaning": "Version of the RS formula behind the ratings.", "internal": true},
    "market_rs_run_id": {"group": "data_quality", "type": "integer", "unit": "none", "meaning": "Internal id of the market RS run.", "internal": true},
    "rs_universe_size": {"group": "data_quality", "type": "integer", "unit": "count", "meaning": "Stocks in the market's RS ranking, which can be fewer than its rows.", "internal": true}
  }
}
