{
  "$comment": "Canonical launch checklist. The /docs/launch-checklist/ page renders this; /campaigns/<key>/ hubs join it with registry/campaigns.json's per-campaign checklist booleans and with registry/status.json's automated step checks (ty_pages_reachable, pixel_firing, mirror_redirect_confirmed — those are derived from status.json, not from this file).",

  "items": [
    {
      "key":   "checkout_live",
      "label": "Checkout live on all paid tiers",
      "definition_of_done": "Each paid tier (main, bump, oto1, oto2) returns a non-error checkout URL from the processor. Test-payment must have completed end-to-end at least once per tier.",
      "automated": true,
      "automated_via": "registry/status.json: every step with product_id + checkout_url_pattern must have checks.checkout_link_valid = true."
    },
    {
      "key":   "test_pay_verified",
      "label": "Test-payment verified for each tier",
      "definition_of_done": "One successful test transaction has run through the processor for each paid tier using the processor's test mode. A short note in the campaign's notes field should record when this was last done.",
      "automated": false
    },
    {
      "key":   "ty_pages_reachable",
      "label": "All thank-you pages reachable and firing conversion events",
      "definition_of_done": "Both ty_core and ty_case paths return 200 and include the conversion_event string in the page body.",
      "automated": true,
      "automated_via": "registry/status.json: steps.ty_core.checks.reachable + markers_present + conversion_event_present."
    },
    {
      "key":   "refund_policy_linked",
      "label": "Refund / chargeback policy linked from checkout",
      "definition_of_done": "Every paid tier's checkout page links to a refund-policy URL that loads in 1 hop. Reviewed by ops on a quarterly cadence.",
      "automated": false
    },
    {
      "key":   "legal_page_reachable",
      "label": "Legal / terms page reachable from footer",
      "definition_of_done": "The terms + privacy pages load (200) and the campaign's footer links to them on every page in the funnel.",
      "automated": false
    },
    {
      "key":   "pixel_firing",
      "label": "Tracking pixel firing on every step",
      "definition_of_done": "The pixel_id declared in registry/campaigns.json appears in the body of every step in the funnel (sales, core, bump, oto1, oto2, ty_core, ty_case).",
      "automated": true,
      "automated_via": "registry/status.json: every step's checks.pixel_present must be true."
    },
    {
      "key":   "mirror_redirect_confirmed",
      "label": "Legacy .html redirects → canonical paths",
      "definition_of_done": "Each legacy .html path in registry/mirror-map.json redirects (301/302) to the canonical /<key>/<step>/ path, and the chain ends on a status that matches what campaigns.json declares.",
      "automated": true,
      "automated_via": "registry/status.json: every step's checks.mirror_redirect_ok must be true."
    },
    {
      "key":   "assets_uploaded",
      "label": "All creatives uploaded to /campaigns/<key>/assets/",
      "definition_of_done": "Every file referenced by campaigns.json's assets[] exists at /campaigns/<key>/assets/<file> and is openable (not a 404).",
      "automated": false
    },
    {
      "key":   "utm_validated",
      "label": "UTM template validated against live ads",
      "definition_of_done": "A live ad run has been launched with the UTM template from campaigns.json applied; the template's pre-substituted sample (in the hub page) renders a valid URL with five expected utm_* parameters and the campaign key.",
      "automated": false
    },
    {
      "key":   "planner_scenario_saved",
      "label": "Media planner scenario saved with current prices",
      "definition_of_done": "A snapshot of the /plan/ calculator at current prices and assumptions has been saved (URL hash captured) and the link is in the campaign's notes or owner's bookmarks.",
      "automated": false
    }
  ]
}
