{
  "title": "FDA advisory meeting watchlist",
  "description": "Track FDA advisory meeting dates, agendas, cancellations and briefing document links. Compare saved observations with source evidence. No paid API, inferred tickers or approval predictions.",
  "type": "object",
  "schemaVersion": 1,
  "properties": {
    "meetingUrls": {
      "title": "FDA meeting page URLs",
      "type": "array",
      "editor": "stringList",
      "description": "Up to 40 individual HTTPS www.fda.gov advisory committee calendar meeting page URLs. Nonempty input uses only these pages. Omitted or empty discovers meetings from the selected official index.",
      "default": [],
      "prefill": [],
      "sectionCaption": "1 - Meetings to inspect",
      "sectionDescription": "One meeting per default run. Two source requests are spaced by 30 seconds, normally finishing in under 60 seconds."
    },
    "discoverySource": {
      "title": "Discovery index",
      "type": "string",
      "editor": "select",
      "enum": [
        "calendar",
        "recent"
      ],
      "enumTitles": [
        "Calendar: upcoming first",
        "Recently updated materials"
      ],
      "description": "Used only when meetingUrls is empty. Omitted uses calendar, with upcoming dates first and most recent past meetings if none are upcoming. Recent sorts meetings by the source index material date. The bounded index is not a complete historical archive.",
      "prefill": "calendar"
    },
    "keywords": {
      "title": "Product or committee terms",
      "type": "array",
      "editor": "stringList",
      "description": "Up to 20 case-insensitive terms. A meeting must match at least one in its title or extracted agenda. Pages are selected before this filter, so raise maxMeetings when a narrow filter matches no selected page.",
      "default": []
    },
    "dateFrom": {
      "title": "Meeting date from",
      "type": "string",
      "editor": "textfield",
      "description": "Optional inclusive meeting date YYYY-MM-DD. Applies to discovery and explicit pages."
    },
    "dateTo": {
      "title": "Meeting date through",
      "type": "string",
      "editor": "textfield",
      "description": "Optional inclusive meeting date YYYY-MM-DD."
    },
    "watchlistLabel": {
      "title": "Your watchlist label",
      "type": "string",
      "editor": "textfield",
      "description": "Optional label copied into every row. This is your annotation, not a verified ticker, company mapping or FDA declaration."
    },
    "maxMeetings": {
      "title": "Maximum meeting pages",
      "description": "Maximum pages selected and attempted per run, after discovery date filtering and before keyword filtering. At least 30 seconds separates source requests. Remaining unselected candidates are counted in SUMMARY.",
      "type": "integer",
      "default": 1,
      "minimum": 1,
      "maximum": 40,
      "sectionCaption": "2 - Observation limits"
    },
    "maxResults": {
      "title": "Maximum saved meetings",
      "description": "Maximum confirmed dataset rows. Each row is one meeting observation including its document link inventory. Skipped unchanged meetings do not use this allowance.",
      "type": "integer",
      "default": 10,
      "minimum": 1,
      "maximum": 1000
    },
    "comparePrevious": {
      "title": "Compare saved observations",
      "type": "boolean",
      "default": false,
      "description": "First comparison emits new observations. Later runs report changed or unchanged fields and added, removed or revised document links. Only confirmed saved rows advance the named history.",
      "sectionCaption": "3 - Saved comparisons",
      "sectionDescription": "Keep the same watchlist and comparison name between sequential runs. The first run saves a baseline; later runs can report changed or unchanged observations."
    },
    "onlyChanges": {
      "title": "Save only new or changed meetings",
      "type": "boolean",
      "default": false,
      "description": "Implies comparePrevious. The first run saves new observations; a fully unchanged repeat correctly saves zero rows. Does not infer missing meetings or cancellations."
    },
    "snapshotName": {
      "title": "Saved comparison name",
      "type": "string",
      "editor": "textfield",
      "description": "1-80 letters, numbers, underscores or hyphens. History is also scoped to source selection, URL watchlist, dates and keywords. Use one writer per namespace; overlapping runs are unsupported.",
      "default": "default"
    },
    "stateStoreName": {
      "title": "History store name",
      "type": "string",
      "editor": "textfield",
      "description": "3-63 letters, numbers or hyphens. Read and written only when comparisons are enabled. A dedicated store isolates your workflow.",
      "default": "maydit-fda-advisory-watchlists"
    },
    "maxRequests": {
      "title": "Maximum FDA requests",
      "description": "Maximum source HTTP requests, including the discovery index. No retries, redirects, PDF downloads or secondary hosts are fetched. Default discovery needs two requests.",
      "type": "integer",
      "default": 8,
      "minimum": 1,
      "maximum": 50,
      "sectionCaption": "4 - Request and time budget",
      "sectionDescription": "Source requests are spaced by at least 30 seconds. Use exact meeting URLs for a focused watchlist and review SUMMARY for gaps."
    },
    "maxRunSeconds": {
      "title": "Run budget in seconds",
      "description": "Includes request spacing, source work and history. Also constrained by the platform deadline minus 25 seconds. Default two-request discovery normally takes about 31 seconds; allow roughly 30 seconds for each additional page.",
      "type": "integer",
      "default": 240,
      "minimum": 30,
      "maximum": 900
    }
  }
}
