{
 "api_version": "v1",
 "site": "https://www.insightintochina.com",
 "generated_at": "2026-10-13T12:41:48.282Z",
 "license": {
  "id": "IIC-Data-1.0 (CC BY 4.0 compatible)",
  "license_url": "https://creativecommons.org/licenses/by/4.0/",
  "summary": "Free to use, quote and redistribute with attribution and a link back to the source URL. Released under Creative Commons Attribution 4.0 (CC BY 4.0); the requests below are not conditions of the licence.",
  "terms": [
   "Attribution: credit \"InsightIntoChina\" and link to the source URL of the dataset or report you used. This is what CC BY 4.0 requires.",
   "Do not state or imply that InsightIntoChina endorses you, your product or your conclusions.",
   "Derived figures must state that they are derived — do not present our classification or scoring as your own measurement.",
   "Facts and figures originate from third-party Chinese-language institutional research. InsightIntoChina structures and translates them; it does not verify them.",
   "Nothing published here is a buy or sell call, a rating, a price target, or investment advice."
  ],
  "requests": [
   "We ask that you do not resell this as a standalone data product. This is a request, not a condition — the CC BY 4.0 licence above permits commercial use."
  ]
 },
 "notes": [
  "All URLs are absolute and stable. Paths marked with {YYYY-MM-DD} are per-day files.",
  "row_count is the number of records in the file as built; it is also the field to watch if you cache.",
  "Subscriber-only fields are never present in these files. See datasets[].fields for the exact schema."
 ],
 "datasets": [
  {
   "id": "catalog",
   "title": "Dataset catalog",
   "path": "/data/index.json",
   "url": "https://www.insightintochina.com/data/index.json",
   "format": "json",
   "cadence": "each deploy",
   "producer": "pipeline/gen-data-api.mjs",
   "description": "This list, in machine-readable form — every public dataset with its schema, row count and update time. Machines should start here.",
   "fields": [
    {
     "name": "api_version",
     "type": "string",
     "note": "Schema version of the public data namespace."
    },
    {
     "name": "generated_at",
     "type": "string",
     "note": "ISO 8601 timestamp of the build that produced these files."
    },
    {
     "name": "site",
     "type": "string",
     "note": "Canonical origin. All dataset URLs resolve under it."
    },
    {
     "name": "license",
     "type": "object",
     "note": "licence id, summary, license_url, terms[] (conditions) and requests[] (non-binding asks). The dataset licence is CC BY 4.0."
    },
    {
     "name": "datasets",
     "type": "array",
     "note": "One object per dataset: id, title, url, format, cadence, description, row_count, bytes, updated_at, fields, provenance, limitations."
    }
   ],
   "provenance": "Assembled at build time by pipeline/gen-data-api.mjs from this repository. Row counts and byte sizes are measured from the files on disk as they are published — none of them is estimated.",
   "limitations": [
    "Describes the datasets, not the market. This file carries no market figures of its own.",
    "An optional dataset with no instance this build (for example the share images on a day the renderer did not run) is removed from datasets[] entirely rather than listed with zero rows, so a missing entry means \"none produced yet\", not \"broken\".",
    "license.requests[] are non-binding asks, not licence conditions — the licence is CC BY 4.0 and it permits commercial use. Only license.terms[] is stated as a condition, and those terms do not narrow CC BY 4.0 beyond attribution and non-endorsement."
   ],
   "row_count": 9,
   "row_unit": "datasets",
   "bytes": 22485,
   "updated_at": "2026-10-13T12:41:48.282Z"
  },
  {
   "id": "daily-digests",
   "title": "Daily digest index",
   "path": "/data/daily/manifest.json",
   "url": "https://www.insightintochina.com/data/daily/manifest.json",
   "format": "json",
   "cadence": "daily (after each build)",
   "producer": "pipeline/gen-daily-report.mjs",
   "description": "Every trading day for which a sector-grouped digest was produced, with how many briefs it covers and how many sectors they fell into.",
   "fields": [
    {
     "name": "generated_at",
     "type": "string",
     "note": "ISO 8601 build timestamp."
    },
    {
     "name": "days",
     "type": "object",
     "note": "Map of YYYY-MM-DD → { total, industryCount, otherRatio }. otherRatio is the share of briefs the sector classifier could not place."
    },
    {
     "name": "order",
     "type": "array",
     "note": "Date strings, newest first. Same order as the human index at /daily."
    }
   ],
   "provenance": "Derived from the same briefing database the site publishes, one entry per trading day that produced a digest. Counts are read back from each day’s own digest file rather than counted a second time.",
   "limitations": [
    "Covers only trading days on which a digest was produced. The earliest day held is 2026-09-27; there is no earlier history.",
    "otherRatio is our classifier’s failure rate, not a market measure. A high value means the taxonomy did not fit that day, not that the market was unusual."
   ],
   "row_count": 16,
   "row_unit": "days",
   "bytes": 1813,
   "updated_at": "2026-10-13T12:41:48.282Z"
  },
  {
   "id": "daily-digest-day",
   "title": "Single-day digest",
   "path": "/data/daily/{YYYY-MM-DD}.json",
   "url": "https://www.insightintochina.com/data/daily/{YYYY-MM-DD}.json",
   "format": "json",
   "cadence": "daily (after each build)",
   "producer": "pipeline/gen-daily-report.mjs",
   "description": "One day’s briefs grouped into sectors, with tone distribution per sector, the representative views, the tickers mentioned most, market breadth and the divergence board.",
   "fields": [
    {
     "name": "date",
     "type": "string",
     "note": "Trading day, YYYY-MM-DD."
    },
    {
     "name": "headlines",
     "type": "array",
     "note": "Up to 3 cross-sector stories: lake_id, title, bottom_line, sentiment, tickers, industryId, industryEn. Restricted to briefs whose sector came from the headline, not from the body."
    },
    {
     "name": "industries",
     "type": "array",
     "note": "Sector sections, sorted by brief count. Each: id, en, zh, noteCount, highConfidenceCount, sentiment{}, tickers[], leaders[], keyDataPoints[]."
    },
    {
     "name": "other",
     "type": "object|null",
     "note": "Briefs the classifier could not place. Kept separate from industries[] rather than folded into one."
    },
    {
     "name": "sentiment",
     "type": "object",
     "note": "counts{} per tone bucket, unknownSentiment, bullRatio (null when nothing was rated), netTone, scoredCount, bullCount, bearCount."
    },
    {
     "name": "stats",
     "type": "object",
     "note": "total, classified, other, otherRatio, viaBody, industryCount, insufficient, minRequired. insufficient=true means too few briefs for a representative digest."
    },
    {
     "name": "regime",
     "type": "object|null",
     "note": "Market breadth reading used: fg_score, fg_label, pct_above_ma20, adv_cnt, dec_cnt, median_ret_20d, as_of_date."
    },
    {
     "name": "board",
     "type": "array",
     "note": "Names where research tone and price diverge most: ticker, gap, ret_1d, ret_20d, note_cnt, senti_score, last_close."
    }
   ],
   "provenance": "Built for one trading day from the briefs published that day. Sector assignment is a deterministic keyword classifier over each headline, with the body used only as a fallback. Tone buckets come from the same per-brief scores the site shows, and board is the same divergence computation described at /methodology.",
   "limitations": [
    "Figures in the briefs originate from third-party Chinese-language institutional research. We translate and structure them; we do not verify them.",
    "Sector labels are a navigation aid, not an analyst judgment. stats.otherRatio is the share the classifier could not place — treat it as the error budget for that day.",
    "A day with too few briefs is flagged stats.insufficient rather than padded out to look representative. Several days in the archive are like this: 2026-10-05 carries 5 briefs, 2026-10-02 carries 7.",
    "board is empty on days when no scored cross-section was available (for example non-trading days), so an empty array is a normal state, not a failure.",
    "Subscriber-only fields are excluded by construction. There is no flag to include them."
   ],
   "row_count": 38,
   "row_unit": "days",
   "bytes": 24724,
   "updated_at": "2026-10-13T12:41:48.282Z"
  },
  {
   "id": "divergence-latest",
   "title": "Divergence board — latest",
   "path": "/data/divergence/latest.json",
   "url": "https://www.insightintochina.com/data/divergence/latest.json",
   "format": "json",
   "cadence": "daily",
   "producer": "pipeline/gen-data-api.mjs",
   "description": "The names where the tone of published research and the price move disagree most, as of the most recent scored trading day. Gap = tone percentile minus 20-day return percentile.",
   "fields": [
    {
     "name": "as_of_date",
     "type": "string",
     "note": "Trading day the board was computed for."
    },
    {
     "name": "score_note",
     "type": "string",
     "note": "Plain-language definition of gap, repeated so a consumer does not have to fetch /methodology."
    },
    {
     "name": "rows",
     "type": "array",
     "note": "ticker, gap, ret_1d, ret_20d, note_cnt, senti_score, last_close. Sorted by gap, descending."
    }
   ],
   "provenance": "Computed from the same scored rows as the divergence board page: gap = tone percentile minus 20-day return percentile, rounded to four decimals. The percentile basis is the scored cross-section of that single trading day, so a gap is comparable within a date and not across dates.",
   "limitations": [
    "A description of disagreement between two measurements. It is not a prediction, a rating, a price target or a recommendation.",
    "The tone input derives from third-party institutional research; only the comparison between tone and return is ours.",
    "Cross-sections are small. The widest day we have scored carries about 600 names. This file holds a single day — for the accumulated history use /data/divergence/history.json.",
    "Rows are deduplicated by ticker keeping the larger absolute gap, so a name that qualified on both sides appears once. sides{} reports how many rows each side contributed before deduplication."
   ],
   "row_count": 50,
   "row_unit": "tickers",
   "bytes": 9498,
   "updated_at": "2026-10-13T12:41:48.282Z"
  },
  {
   "id": "divergence-history",
   "title": "Divergence board — accumulated panel",
   "path": "/data/divergence/history.json",
   "url": "https://www.insightintochina.com/data/divergence/history.json",
   "format": "json",
   "cadence": "daily (appends one cross-section per scored trading day)",
   "producer": "pipeline/gen-divergence-panel.mjs",
   "description": "Every scored trading day the board has covered, one row per ticker — the accumulated history behind the single-day board. It is appended to, not mirrored, so a day stays in the file even after the source view stops serving it.",
   "fields": [
    {
     "name": "schema",
     "type": "string",
     "note": "Format version of this file."
    },
    {
     "name": "source_view",
     "type": "string",
     "note": "The view the rows are read from."
    },
    {
     "name": "primary_key",
     "type": "array",
     "note": "[\"as_of_date\", \"ticker\"] — unique across the whole file."
    },
    {
     "name": "units",
     "type": "object",
     "note": "The unit of each measure. gap and senti_score are 0–1; ret_1d and ret_20d are already multiplied by 100."
    },
    {
     "name": "rows_per_day",
     "type": "object",
     "note": "Map of YYYY-MM-DD → row count. Read this before treating a date as a panel observation: a day with a handful of rows is a test run, not a cross-section."
    },
    {
     "name": "days",
     "type": "array",
     "note": "Every date present in rows[], ascending."
    },
    {
     "name": "days_no_longer_in_source",
     "type": "array",
     "note": "Dates still in this file that the source view no longer serves. Kept deliberately — that is what \"accumulated\" means."
    },
    {
     "name": "count",
     "type": "number",
     "note": "Total rows; equals rows.length."
    },
    {
     "name": "rows",
     "type": "array",
     "note": "as_of_date, ticker, gap, ret_1d, ret_20d, note_cnt, senti_score, last_close."
    }
   ],
   "provenance": "Accumulated from the same divergence_daily_view the board pages read, one cross-section per scored trading day. Each day is re-fetched on every run and replaced whole — but only after its row count is reconciled against the count the source view declares for itself (divergence_dates_view.rows_cnt). A day that fails reconciliation keeps its previous rows rather than being half-replaced. Days the source no longer serves are kept. The file carries no timestamp, so it is byte-for-byte reproducible from the source view.",
   "limitations": [
    "Three complete cross-sections so far (2026-09-24 with 580 rows, 2026-10-08 with 626, 2026-10-09 with 555). 2026-09-18 (5 rows) and 2026-10-07 (6 rows) are functional test runs, not full cross-sections — check rows_per_day before using a date as a panel observation.",
    "gap is computed against that day’s own cross-section, so it is comparable within a date and not across dates. A gap of +0.8 on one day does not mean the same thing as +0.8 on another.",
    "Units are mixed, because they are the units the source uses: gap and senti_score are 0–1, ret_1d and ret_20d are already percentages, and last_close is unadjusted for splits or dividends.",
    "The tone input is our scoring of third-party research; only the comparison between tone and return is ours.",
    "Depth grows one cross-section per scored trading day. Days the pipeline did not score cannot be back-filled, so a gap in days[] is permanent.",
    "Nothing here is a buy or sell call, a rating, a price target or investment advice."
   ],
   "row_count": 2416,
   "row_unit": "rows",
   "bytes": 463706,
   "updated_at": "2026-10-13T12:41:48.282Z"
  },
  {
   "id": "notes-latest",
   "title": "Latest institutional briefs",
   "path": "/data/notes/latest.json",
   "url": "https://www.insightintochina.com/data/notes/latest.json",
   "format": "json",
   "cadence": "daily",
   "producer": "pipeline/gen-data-api.mjs",
   "description": "The most recently published briefs with their headline, one-line bottom line, tone and mentioned tickers — the same public fields the site shows, in the order they were published.",
   "fields": [
    {
     "name": "generated_at",
     "type": "string",
     "note": "ISO 8601 build timestamp."
    },
    {
     "name": "count",
     "type": "number",
     "note": "Number of briefs included."
    },
    {
     "name": "rows",
     "type": "array",
     "note": "published_at, lake_id, title_en, bottom_line, sentiment_score, tickers[], key_data_points[], industry (our classifier’s sector id)."
    },
    {
     "name": "excluded_fields",
     "type": "array",
     "note": "Names of the subscriber-only fields deliberately not included, with the reason."
    }
   ],
   "provenance": "The public fields of the most recently published briefs, in publication order, read from the same masked database view that serves logged-out visitors. The industry value is added by our classifier and is labelled as such inside the file, because who assigned a label decides how it may be cited.",
   "limitations": [
    "Headlines and bottom lines are our English renderings of third-party Chinese-language research. The argument belongs to the named source institution; cite that institution too.",
    "sentiment_score is our scoring of the source text, not the source’s own rating. Do not restate it as the research house’s view.",
    "key_data_points are figures taken from the source material. They are not independently verified by us.",
    "Only the newest 50 briefs are present, so this file is a window and not an archive. Use the per-day digests for history.",
    "excluded_fields lists every subscriber-only field by name and reason. A reader can tell what was withheld rather than having to guess."
   ],
   "row_count": 50,
   "row_unit": "briefs",
   "bytes": 25815,
   "updated_at": "2026-10-13T12:41:48.282Z"
  },
  {
   "id": "tickers-index",
   "title": "Ticker index",
   "path": "/data/tickers-index.json",
   "url": "https://www.insightintochina.com/data/tickers-index.json",
   "format": "json",
   "cadence": "daily (after each build)",
   "producer": "pipeline/gen-tickers-index.mjs",
   "description": "Every ticker with at least one published brief, with its note count. Keys are abbreviated because this file is also loaded by the site’s own /tickers page — the schema below is the contract.",
   "fields": [
    {
     "name": "[].s",
     "type": "string",
     "note": "Ticker symbol, e.g. 300308.SZ. Sorted ascending by code unit order."
    },
    {
     "name": "[].n",
     "type": "string",
     "note": "Company name (may be empty)."
    },
    {
     "name": "[].c",
     "type": "number",
     "note": "Number of published briefs whose tickers[] contains this symbol. Always > 0 here."
    }
   ],
   "provenance": "Every ticker appearing in at least one published brief, with the count of briefs that mention it. Rebuilt from the same briefing database as the rest of the site; the symbol list is derived from tickers[] on the briefs themselves.",
   "limitations": [
    "A coverage count, not a ranking. A high count means our sources wrote about it often, not that it is more important, more liquid or better regarded.",
    "Company names are best-effort and may be empty for thinly covered symbols.",
    "Absence means \"not mentioned in any brief we hold\", not \"not listed on the exchange\". The index covers only names our sources named.",
    "Symbol suffixes follow the market of listing (.SZ / .SH / .SS / .HK) as they appear in the source material; they are not normalised across vendors."
   ],
   "row_count": 2481,
   "row_unit": "tickers",
   "bytes": 113230,
   "updated_at": "2026-10-13T12:41:48.282Z"
  },
  {
   "id": "daily-posters",
   "title": "Daily share images",
   "path": "/daily/{YYYY-MM-DD}.png",
   "url": "https://www.insightintochina.com/daily/{YYYY-MM-DD}.png",
   "format": "png",
   "cadence": "daily on trading days (best-effort)",
   "producer": "pipeline/gen-posters.mjs + pipeline/shot-poster.py",
   "description": "A ready-to-post picture of each day’s sector breakdown — the same content as the digest page, laid out for social feeds. Only exists for trading days where a digest was produced; days without one have no image, and the digest page simply shows no share link.",
   "fields": [
    {
     "name": "(binary)",
     "type": "png",
     "note": "PNG, 1080×1350 logical pixels captured at 2× device scale (2160×2700 px)."
    },
    {
     "name": "content",
     "type": "string",
     "note": "Date, brief and sector counts, market breadth, and up to 5 sector cards each with tone distribution and a one-line representative view."
    },
    {
     "name": "coverage",
     "type": "string",
     "note": "Not every calendar day. Follow the <enclosure> in /feed.xml or the links listed at /daily for the days that have one."
    }
   ],
   "provenance": "A screenshot of that day’s digest page: rendered headlessly at 1080×1350 logical pixels, captured at 2× device scale, written next to the page it depicts.",
   "limitations": [
    "Best-effort by design. Production depends on a browser rendering channel, so some trading days have no image and the digest page simply shows no share link. A missing day is not a failed digest.",
    "The image follows the digest page exactly. It adds no figure that is not already in the JSON, so it is the wrong thing to parse — use the dataset files for anything computed.",
    "The updated_at on this entry is the PNG’s real file mtime, not the build time, because the image can legitimately lag the build by a day."
   ],
   "row_count": 10,
   "row_unit": "images",
   "bytes": 596599,
   "updated_at": "2026-10-13T12:41:27.063Z"
  },
  {
   "id": "feed",
   "title": "RSS feed — daily digests",
   "path": "/feed.xml",
   "url": "https://www.insightintochina.com/feed.xml",
   "format": "rss",
   "cadence": "daily (after each build)",
   "producer": "pipeline/gen-feed.mjs",
   "description": "RSS 2.0 feed of the daily digests, newest first. Each item links to the full digest and carries a plain-text summary of that day’s sector breakdown.",
   "fields": [
    {
     "name": "channel/item/title",
     "type": "string",
     "note": "China Institutional Research Digest — YYYY-MM-DD"
    },
    {
     "name": "channel/item/link",
     "type": "string",
     "note": "Absolute URL of the digest page."
    },
    {
     "name": "channel/item/pubDate",
     "type": "string",
     "note": "RFC 822 date."
    },
    {
     "name": "channel/item/guid",
     "type": "string",
     "note": "Stable, never reused: the digest URL."
    },
    {
     "name": "channel/item/description",
     "type": "string",
     "note": "Plain-text digest: brief count, sector breakdown with tone, and the top stories."
    },
    {
     "name": "channel/item/enclosure",
     "type": "string",
     "note": "Present only on days that have a share image: url, length (real byte count), type=image/png."
    }
   ],
   "provenance": "RSS 2.0 built from the same digest files the site publishes, newest first. The guid is the digest URL, which is stable and never reused, so subscribers do not see the same day twice.",
   "limitations": [
    "The description carries the same public text as the digest page and nothing more. Subscriber-only fields never appear in the feed.",
    "The <enclosure> is present only on days that have a share image, so a subscriber cannot rely on a picture every day.",
    "The feed window is bounded — it is a rolling list, not an archive. Use the per-day files at /data/daily for the full history."
   ],
   "row_count": 16,
   "row_unit": "items",
   "bytes": 39561,
   "updated_at": "2026-10-13T12:41:48.282Z"
  }
 ]
}
