{
  "title": "Podcast episodes - choose public feeds",
  "type": "object",
  "schemaVersion": 1,
  "properties": {
    "feedUrls": {
      "title": "Public podcast feed URLs",
      "type": "array",
      "editor": "stringList",
      "description": "Up to 20 public RSS 2.0 or Atom feeds. Only HTTP(S); no credentials, private networks or blocked robots paths. Omitted/empty input uses NASA Curious Universe as a small public demo.",
      "items": {
        "type": "string"
      },
      "prefill": [
        "https://www.nasa.gov/feeds/podcasts/curious-universe"
      ],
      "sectionCaption": "1 · Podcast feeds",
      "sectionDescription": "Supply explicit public feed URLs."
    },
    "keywords": {
      "title": "Topic words or phrases",
      "type": "array",
      "editor": "stringList",
      "items": {
        "type": "string"
      },
      "description": "Optional: up to 20 literal case-insensitive phrases, each at most 100 characters. Match episode titles and the first 100,000 characters of normalized show notes. Matching excerpts are included. No semantic or sentiment inference.",
      "sectionCaption": "2 · Episode filters",
      "sectionDescription": "Match returned show notes or titles and optionally narrow publication dates."
    },
    "keywordMode": {
      "title": "Topic match rule",
      "type": "string",
      "editor": "select",
      "enum": [
        "any",
        "all"
      ],
      "enumTitles": [
        "Any phrase",
        "Every phrase"
      ],
      "default": "any",
      "description": "Require any or all keyword phrases. An empty keywords list keeps all episodes."
    },
    "publishedAfter": {
      "title": "Published on or after",
      "type": "string",
      "editor": "textfield",
      "description": "Optional real YYYY-MM-DD date, inclusive at 00:00 UTC. Episodes without a parseable publication date are excluded when this filter is used."
    },
    "maxEpisodesPerFeed": {
      "title": "Maximum episodes inspected per feed",
      "type": "integer",
      "editor": "number",
      "minimum": 1,
      "maximum": 1000,
      "default": 100,
      "description": "Inspect this many most recently published usable episodes per currently visible feed. Unknown dates follow dated entries. The feed may not contain the complete archive; disappearing entries are never declared deleted.",
      "sectionCaption": "3 · Feed and result limits",
      "sectionDescription": "The inspected feed window and saved-result cap are separate limits."
    },
    "maxResults": {
      "title": "Maximum saved episodes",
      "type": "integer",
      "editor": "number",
      "minimum": 1,
      "maximum": 1000,
      "default": 20,
      "description": "Maximum unique matching episodes saved across all feeds. A normal requested result cap is bounded coverage, not a source failure."
    },
    "onlyNewOrChanged": {
      "title": "Only new or edited episodes",
      "type": "boolean",
      "editor": "checkbox",
      "default": false,
      "description": "Use named-store history to emit only new or changed matching episodes. First observations return matching episodes. Only successfully saved rows advance history; unchanged reruns can correctly return zero. Use one concurrent run per snapshot scope.",
      "sectionCaption": "4 · Saved comparisons",
      "sectionDescription": "The first comparison establishes history. Reuse the same scope for later observations and avoid concurrent writers."
    },
    "snapshotName": {
      "title": "History name",
      "type": "string",
      "editor": "textfield",
      "default": "default",
      "description": "Name 1–100 characters. History also includes the sorted feeds, topic filters, date filter and per-feed window. Different scopes do not share baselines. No effect unless onlyNewOrChanged is true."
    },
    "maxRunSeconds": {
      "title": "Run time budget (seconds)",
      "type": "integer",
      "editor": "number",
      "default": 240,
      "minimum": 30,
      "maximum": 3600,
      "description": "All requests respect this wall-clock budget and the platform deadline minus 25 seconds. Default 240 seconds. Partial coverage and spending stops are explicit in SUMMARY.",
      "sectionCaption": "5 · Advanced run settings",
      "sectionDescription": "Adjust the time budget only when a larger collection needs it."
    }
  },
  "description": "Supply public podcast feed URLs, select a visible episode window and apply optional literal topic filters. Saved comparisons can track newly observed or edited entries; audio is not downloaded."
}
