← back to Dw Yolo Loop

scripts/preflight/rules.json

91 lines

{
  "_meta": {
    "name": "DW pre-flight validator ruleset",
    "version": "1.0.0",
    "created": "2026-06-14",
    "sources": [
      "~/.claude/CLAUDE.md (global standing rules)",
      "~/.claude/projects/-Users-stevestudio2-Projects-designerwallcoverings/memory/MEMORY.md",
      "~/Projects/_shared/sku-redact.js (canonical VENDORS denylist)"
    ],
    "note": "Machine-checkable HARD rules only. Each rule names the field(s) it reads; a rule is reported N/A (not PASS) when none of its required fields are present in the payload. Fail-closed: any non-N/A FAIL => validator exits non-zero.",
    "house_brands": [
      "phillipe romano", "philippe romano", "hollywood", "artmura", "saybrook house",
      "designer wallcoverings", "architectural wallcoverings", "novasuede"
    ]
  },
  "rules": [
    {
      "id": "wallpaper-banned",
      "severity": "error",
      "title": "Word 'Wallpaper' banned in DW catalog text (use 'Wallcovering')",
      "rationale": "CLAUDE.md / MEMORY: DW catalog titles/copy/tags must say 'Wallcovering', never 'Wallpaper'.",
      "applies_to_fields": ["title", "body_html", "description", "tags", "product_type"],
      "check": "no_word_wallpaper",
      "_note": "Whole-word, case-insensitive. Skips well-known proper-noun exceptions (e.g. vendor brand 'Madagascar Wallpaper') only when matched inside a denylisted vendor token already flagged elsewhere; here we flag plain 'wallpaper' occurrences."
    },
    {
      "id": "no-unknown-in-title",
      "severity": "error",
      "title": "Never 'Unknown' in a Shopify title",
      "rationale": "MEMORY/standing rule: a title containing 'Unknown' is a data defect.",
      "applies_to_fields": ["title"],
      "check": "no_unknown_token"
    },
    {
      "id": "sample-trap-425",
      "severity": "error",
      "title": "$4.25 must never be a ROLL / non-sample variant price (sample-trap)",
      "rationale": "MEMORY 425-sample-price-policy: $4.25 is the memo-SAMPLE variant ONLY. A roll/non-sample variant priced at 4.25 (or a product-level price read of 4.25) is the $4.25 garbage bug.",
      "applies_to_fields": ["variants", "retail_price", "net_price", "price"],
      "check": "no_425_on_roll_variant",
      "sample_value": 4.25
    },
    {
      "id": "kravet-map-floor",
      "severity": "error",
      "title": "Kravet-family price must be >= wholesale x 1.5 (MAP floor)",
      "rationale": "CLAUDE.md kravet-lines-price-at-map: every Kravet-umbrella brand sells at MAP = WHLS cost x 1.5. A retail below that floor is off-MAP and non-compliant.",
      "applies_to_fields": ["vendor", "title", "tags", "cost", "net_price", "whls_cost", "retail_price", "price", "variants"],
      "check": "kravet_map_floor",
      "map_multiplier": 1.5,
      "kravet_family": [
        "kravet", "lee jofa", "lee jofa modern", "groundworks", "brunschwig",
        "cole and son", "cole & son", "gp j baker", "gp & j baker", "colefax",
        "clarke and clarke", "clarke & clarke", "mulberry", "threads",
        "baker lifestyle", "andrew martin", "nicolette mayer", "aerin",
        "barclay butera", "thom filicia", "kravet couture", "kravet design",
        "kravet contract", "kravet basics"
      ]
    },
    {
      "id": "active-needs-image-width-inventory",
      "severity": "error",
      "title": "ACTIVE products need image + width metafield + inventory=2026 on BOTH variants",
      "rationale": "CLAUDE.md/MEMORY: never ACTIVE without image + width metafield; activating any new item sets inventory=2026 on BOTH variants.",
      "applies_to_fields": ["status", "image_url", "images", "metafields", "width", "variants", "inventory"],
      "check": "active_completeness",
      "required_inventory_year": "2026"
    },
    {
      "id": "no-vendor-name-leak",
      "severity": "error",
      "title": "No residual 3rd-party vendor-name leaks (per sku-redact VENDORS denylist)",
      "rationale": "CLAUDE.md/MEMORY: DW vendor names NEVER in customer-facing UI (title/handle/sku/tags/vendor). House brands are allowed. Denylist mirrors _shared/sku-redact.js VENDORS.",
      "applies_to_fields": ["title", "handle", "dw_sku", "sku", "tags", "vendor"],
      "check": "no_denylisted_vendor_token",
      "denylist": [
        "wolf gordon", "nina campbell", "jeffrey stevens", "versace",
        "arte international", "lee jofa modern", "lee jofa", "innovations usa",
        "innovations", "koroseal", "schumacher", "candice olson", "thibaut",
        "maya romanoff", "scalamandre", "dedar", "carnegie", "cole and son",
        "kravet", "clarke and clarke", "brunschwig", "gp j baker", "sandberg",
        "designers guild", "graham and brown", "harlequin", "andrew martin",
        "ronald redding", "blithfield", "coordonne", "fentucci", "sister parish",
        "phillip jeffries", "fromental", "westport", "breegan", "les ensembliers",
        "roger thomas", "stacy garcia"
      ]
    }
  ]
}