{
  "_provenance": "Gate rules assembled 17 Jul 2026. Core claim rules port from the Case 2 creative-gate engine (run-report evidence); availability + lexicon + register rules are new, read from the market catalogs. Rule types: block (variant dies, reason attached), fix (gate applies a deterministic repair), flag (passes to owner with a note). Facts-vs-directives discipline: availability rules READ products/brand data at run time - they are never hard-coded strategy.",
  "rules": [
    {
      "id": "absolute-leak-claim",
      "action": "block",
      "applies": { "brands": ["blood_sg", "blood_my", "ndo_sg"], "channels": "all", "language": "en" },
      "mechanism": "regex",
      "pattern": "(?i)\\b(leak[- ]?free|zero leaks?|no leaks?|leak[- ]?proof)\\b",
      "reason": "Absolute leak claim - contradicted by own 5-star reviewers (side-leak 2023, gush-change 2024, 'leak proof most of the time' 2026). Do-not-say #2.",
      "evidence": "run-report LIVE-COPY AUDIT + V007/V036 refusals",
      "note": "BM equivalents ('anti bocor', 'bebas bocor') run in Blood MY's own live ads - surfaced as an owner question (see register-consistency flag), not silently blocked."
    },
    {
      "id": "ndo-overnight-claim",
      "action": "block",
      "applies": { "brands": ["ndo_sg"], "channels": "all" },
      "mechanism": "regex",
      "pattern": "(?i)\\b(through the night|all[- ]night|overnight (dry|protection|security)|sleep(s)? through)\\b",
      "reason": "NDO overnight claim blocked - product-risk finding: ~25 overnight-leak complaints clustered May-Jun 2026, several traced to fit/cut. Ad spend amplifies whatever is true; overnight claims resume after the fit fix.",
      "evidence": "run-report V040 refusal",
      "expiry": "review on fit-fix ship - dated directive, owner: product"
    },
    {
      "id": "ranking-claim",
      "action": "block",
      "applies": { "brands": "all", "channels": "all" },
      "mechanism": "regex",
      "pattern": "(?i)(#\\s?1|no\\.?\\s?1|number one|best in (singapore|malaysia|sg|my)|malaysia's #?1|singapore's #?1)",
      "reason": "Ranking claim with no ranking evidence on file.",
      "evidence": "corpus absence; Case 1 evidence-tagging discipline"
    },
    {
      "id": "absolute-guarantee",
      "action": "block",
      "applies": { "brands": "all", "channels": "all" },
      "mechanism": "regex",
      "pattern": "(?i)\\b(100%\\s*(guaranteed?|protection|leak)|guaranteed?\\b(?!.*(fit|refund))|forever\\b|never (leak|itch|rash))",
      "reason": "Absolute guarantee - banned claim class. ('100% drug-free' and '100% corn top-sheet' are approved composition claims and do not match.)",
      "evidence": "brand.json do_not_say; Case 2 rule set"
    },
    {
      "id": "clinical-proof",
      "action": "block",
      "applies": { "brands": "all", "channels": "all" },
      "mechanism": "regex",
      "pattern": "(?i)\\b(clinically|dermatologist|medically)\\s+(proven|tested|certified)\\b",
      "reason": "Clinical proof language with no study on file. (NDO pack carries a dermatologist-approved badge - if that substantiation file exists internally, this rule gains a scoped exception; week-1 ingest question.)",
      "evidence": "corpus absence; ndo-social.md badge note"
    },
    {
      "id": "proven-scope",
      "action": "flag",
      "applies": { "brands": "all", "channels": "all" },
      "mechanism": "claims-lookup",
      "check": "any 'proven/terbukti' statement must match an approved_claims scope for that brand-market",
      "reason": "'Proven' phrasing is approved only in the scopes the live copy uses (e.g. terbukti anti bocor dan ruam on MY corn pads); outside those scopes it needs owner sign-off.",
      "evidence": "brand.json approved_claims scopes"
    },
    {
      "id": "availability",
      "action": "block",
      "applies": { "brands": "all", "channels": "all" },
      "mechanism": "catalog-lookup",
      "check": "every product referenced must exist AND be purchasable in the brief's market per products.json (greyed/unreleased variants fail)",
      "reason_template": "{product} is not in the current {market} catalog - don't advertise what can't be bought. (Fact read from the product feed at run time; when the rollout changes, the feed changes and this verdict follows.)",
      "known_cases": ["Hydrating liner: live in MY, greyed on SG Shopee at capture", "Blood has no TikTok Shop; NDO does"],
      "evidence": "products.json; blood-malaysia.md launch_state; video-hooks.md channel asymmetry"
    },
    {
      "id": "platform-lexicon",
      "action": "fix",
      "applies": { "brands": ["blood_sg", "blood_my"], "channels": ["tiktok"] },
      "mechanism": "replace",
      "replacements": { "(?i)\\bsex\\b": "s3x", "(?i)\\bvaginal\\b": "v@ginal" },
      "reason": "TikTok health-content lexicon - Blood's own organic output uses platform-safe spellings.",
      "evidence": "video-hooks.md TikTok set ('5 benefits of having s3x on a period', '5 V@GINAL DISCHARGE TEXTURES')"
    },
    {
      "id": "reel-completeness",
      "action": "fix",
      "applies": { "brands": "all", "channels": ["ig_reel"] },
      "mechanism": "append-check",
      "check": "caption must contain a product name and a destination; if missing, append the standard product+destination line for that brand-market",
      "reason": "Reel captions must carry product + destination per live-format convention.",
      "evidence": "formats.json ig_reel hard rule; blood-malaysia.md reels"
    },
    {
      "id": "register-consistency",
      "action": "flag",
      "applies": { "brands": ["blood_my"], "channels": "all" },
      "mechanism": "model-check",
      "check": "BM copy should code-switch naturally (house register); formal textbook Malay gets flagged as off-brand; BM absolute-leak equivalents ('anti bocor') get flagged with the EN-rule tension noted for the owner",
      "reason": "Register is per-market, per-surface; the EN/BM claim-rule asymmetry is a live owner decision, not a silent default.",
      "evidence": "blood-malaysia.md language pattern + F6/F8"
    },
    {
      "id": "voice-empathy",
      "action": "flag",
      "applies": { "brands": "all", "channels": "all" },
      "mechanism": "model-check",
      "check": "score voice fit 0-10; flag below 6 with the specific betrayal named (e.g. mocking the sufferer, centering partner inconvenience, audience-register mismatch)",
      "reason": "Voice checks that regexes can't reach - the Case 2 model-judge lane.",
      "evidence": "run-report V026 (4/10), V032-V035 audience-fit flags"
    }
  ]
}
