# Changelog of Indian IPO Tracker - SEBI DRHP, GMP & Listing API (`contented_academy/indian-ipo-tracker`) Actor

- **URL**: https://apify.com/contented\_academy/indian-ipo-tracker/changelog.md
- **Full Actor documentation**: https://apify.com/contented\_academy/indian-ipo-tracker.md

## Changelog

### 1.2.0 — 2026-05-05

#### Behavior corrections (semantic break — no compat shim)

- **`documents.drhp_urls[]` now contains direct PDF URLs only.** Previously it
  carried the SEBI HTML detail-page URL (a long-standing bug surfaced by the
  Absolute Projects India test). Consumers that used to fetch and HTML-parse
  the array element should switch to the new `documents.sebi_detail_page_url`
  field for the HTML page. CLAUDE.md confirms there are no live API consumers
  yet, so no compat shim is shipped.

#### Bug fixes

- **`mode: specific`** now actually filters by `ipo_filter` (was a no-op — the
  pipeline always ran full discovery and ignored the filter). Filter is
  applied *before* the `max_ipos` slice; `max_ipos` is ignored entirely in
  specific mode.
- **`preset: track_specific`** without `ipo_filter` is now rejected with a
  fatal `SPECIFIC_MODE_NO_FILTER` error. Previously this combination
  bypassed Zod's `superRefine` because `applyPreset()` mutates `mode` after
  parsing.
- **`mode: specific` with no matches** now exits with `SPECIFIC_MODE_NO_MATCH`
  and a non-zero status (was silent-empty).
- **`prospectus_parse` mode work queue** now populates: every default-mode
  run UPSERTs every IPO into the Postgres `ipos` table (no writer existed
  before). The queue was structurally always empty.
- **SEBI listing-row PDFs**: `parseTitleCell` now collects ALL PDF anchors
  in the title cell, not just the first one (was breaking at first match).
- **SEBI detail-page extra PDFs**: `parseSebiDetail` collects every non-iframe
  PDF anchor on the detail page (corrigenda, observation responses, etc).

#### Additions

- `documents.sebi_detail_page_url` — the SEBI HTML detail page URL.
- `documents.detail_page_scraped` — boolean; distinguishes "scraped, no
  addenda exist" from "scrape failed".
- `documents.classified_urls` — every PDF labelled `drhp` / `rhp` /
  `addendum` / `abridged` / `corrigendum` / `unknown` with its source
  (`sebi-listing-row` / `sebi-detail-iframe` / `sebi-detail-extra`).
- `source_status` — per-source `{attempted, matched, reason, source_url}`
  for `sebi`, `sebi_detail`, `bse`, `nse`. Reason taxonomy: `matched` /
  `no_match_at_drhp_stage` / `scraper_failed` / `not_attempted` /
  `pdf_extraction_failed`. Closes the silent-null gap on BSE/NSE at DRHP
  stage.
- `data_quality_score` is now **computed** from `STAGE_EXPECTED_FIELDS`
  (was hardcoded 0.55/0.4/0.2 ladder).
- `data_quality_detail` — machine-readable breakdown:
  `{stage, expected_fields[], populated_fields[], missing_fields[], score}`.
- `lifecycle.drhp_pdf_content_length` + `lifecycle.drhp_pdf_verified_at` —
  surfaces the HEAD-verification metadata that `verify_drhp_pdf:true`
  already produced internally.
- `prospectus_parse` mode auto-resolves legacy HTML URLs in KV snapshots
  through `scrapeSebiDetail` (one-release backwards-compat shim). Logs
  WARN per legacy URL.

#### Schema/expectation revisions

- `STAGE_EXPECTED_FIELDS.DRHP_FILED` revised: dropped `industry` (always
  null pre-Tier-2 industry classifier — was capping every DRHP record at
  4/5). Added `documents.drhp_urls.0` and `documents.sebi_detail_page_url`.
- `verify_drhp_pdf` description rewritten to clarify HEAD-only behaviour
  and point to the upcoming `parse_drhp_cover` flag (separate plan).

#### Out of scope (deferred to a separate plan)

- DRHP cover-page content extractor (`parse_drhp_cover` flag, dedicated
  extractor for `issue_size_cr` / `fresh_issue_cr` / `ofs_cr` / `face_value`
  / promoter list / registrar). The audit confirmed this needs ~3–5 days
  on its own; the misleading-flag-name half is fixed in 1.2.0 by the
  honest description.
