{
 "defects": [
  {
   "id": "stubs",
   "name": "Pre-listing stub rows",
   "what": "Kite's historical API returns a handful of placeholder rows BEFORE a company's IPO - absurd prices with near-zero volume - separated from the real series by a multi-year date gap.",
   "examples": [
    {
     "symbol": "COHANCE",
     "detail": "Rs 0.30 closes in 2015 before a 2020 listing; would show a +112,250% day"
    },
    {
     "symbol": "MAZDOCK",
     "detail": "literal Rs 0.00 closes in 2017-2018"
    },
    {
     "symbol": "DELHIVERY",
     "detail": "would show a +9,228% day"
    },
    {
     "symbol": "SBICARD",
     "detail": "stub sat at Rs 313 against a Rs 681 IPO - only a 2.2x step, so a price-ratio test alone misses it"
    }
   ],
   "impact": "9 symbols / 519 rows removed. Left in, COHANCE would rank #1 of its year by a factor of ~1,000x.",
   "rule": "A >120-day hole in a daily series is treated as a listing gap and the leading segment dropped."
  },
  {
   "id": "bonus",
   "name": "Unadjusted bonus / split",
   "what": "Kite back-adjusts most corporate actions but demonstrably missed some. An unadjusted bonus inside a financial year fabricates a large SPURIOUS NEGATIVE return, which would push a genuine winner into the bottom 20.",
   "examples": [
    {
     "symbol": "CGPOWER",
     "detail": "+190.7% single-day step on CONSECUTIVE trading days (no date gap) - an unadjusted bonus Kite never fixed"
    },
    {
     "symbol": "SPLPETRO",
     "detail": "2022-06-07, ratio exactly 0.5000 = a 1:1 bonus; repaired by back-adjusting prior prices"
    }
   ],
   "impact": "1 symbol repaired (SPLPETRO).",
   "rule": "Only a single-day drop matching a canonical LARGE ratio (1/2, 1/3, 1/4, 1/5, 1/10) within 1.5% and >=45% deep is treated as an unadjusted bonus."
  },
  {
   "id": "demerger",
   "name": "Demergers",
   "what": "A demerger removes value from the parent on the ex-date while the shareholder receives a SEPARATE security, so the price-only return is not measurable.",
   "examples": [
    {
     "symbol": "TATACHEM",
     "detail": "FY20 - consumer-products demerger into Tata Consumer, ratio 0.438"
    },
    {
     "symbol": "ABFRL",
     "detail": "FY26 - Madura Fashion demerged into ABLBL, ratio 0.441"
    },
    {
     "symbol": "ABREL",
     "detail": "FY20 - scheme of arrangement, ratio 0.446"
    }
   ],
   "impact": "3 stock-FY pairs EXCLUDED from rankings rather than patched.",
   "rule": "Excluded explicitly, never silently adjusted."
  },
  {
   "id": "series",
   "name": "Instrument series changes",
   "what": "An NSE stock can move between series (EQ <-> BE <-> D1) and each series carries a DIFFERENT instrument token whose history covers only its own span. Fetching one token silently truncates the series.",
   "examples": [
    {
     "symbol": "HEG / HFCL",
     "detail": "currently trade in the BE series, so the EQ token's history ends early"
    },
    {
     "symbol": "CHOLAFIN / MOTHERSON",
     "detail": "carry a D1 series"
    },
    {
     "symbol": "BAJAJ-AUTO / NAM-INDIA",
     "detail": "exposed a naive split('-') bug, because their REAL names contain a hyphen"
    }
   ],
   "impact": "All tokens per symbol fetched and stitched; 500/500 universe symbols resolved.",
   "rule": "Resolve every series token for a symbol and stitch, rather than assuming one token per symbol."
  }
 ],
 "reverted_fix": {
  "name": "The over-aggressive fix that was caught and reverted",
  "story": "The first version of the bonus rule accepted any drop matching 4/5, 3/4 or 2/3 within 2.5%. That flagged ~200 ordinary crash days - VEDL and ZENSARTECH on 2020-03-23, ZEEL on 2024-01-23, YESBANK on 2019-10-01 - which are REAL market events, not bonuses. Back-adjusting them would have FABRICATED a ~+25% return for each of those stocks.",
  "detection": "Comparing candidate moves against the index that day separated the two cases: a real crash shows up in the index too, whereas a bonus/split adjustment does not.",
  "resolution": "The rule was tightened to canonical large ratios only, and eight ambiguous 30-45% drops were deliberately left UNMODIFIED and listed for inspection rather than silently patched.",
  "why_it_matters": "This is the kind of error that would have made the backtest look better while making it wrong. The numbers here are post-correction."
 },
 "eligibility": {
  "rules": [
   ">=85% of the Nifty 500's trading days present in that FY",
   "a valid base close within 5 trading days before the FY and an end close within 5 days of FY end",
   "not a demerger exclusion"
  ],
  "note": "This is why the eligible count grows from 316 (FY17) to 473 (FY26): many current constituents had simply not listed in 2016."
 },
 "pipeline": [
  {
   "step": "Fetch",
   "detail": "Kite Connect v3 day candles, 2014-01-01 to 2026-09-11. Kite caps a day request at 2000 days, so every token was fetched in <=1999-day chunks and merged. Rate-limited to ~2.8 req/sec, resumable."
  },
  {
   "step": "Resolve",
   "detail": "500/500 universe symbols mapped to instrument tokens, stitching series changes; 25 macro series (Nifty 500, 17 sector indices, GOLDBEES, SILVERBEES, INDIA VIX, MCX gold/silver/crude)."
  },
  {
   "step": "Audit",
   "detail": "Per-symbol coverage, stale-price runs, extreme daily moves, history start - before computing any statistic."
  },
  {
   "step": "Clean",
   "detail": "Non-positive closes dropped; pre-listing stubs removed; canonical bonus/split repairs applied; demerger pairs excluded."
  },
  {
   "step": "Analyse",
   "detail": "Five analyses over the cleaned panel, all emitted as JSON, tables machine-generated from that JSON."
  }
 ],
 "not_corrected": {
  "dividends": "Returns are price returns, split/bonus-adjusted, but NOT dividend-adjusted. This understates total return, most for high-payout Power, FMCG and PSU names. Sector relative rankings are distorted by roughly the dividend-yield spread."
 }
}