{
  "schema": "si-demand-engine/1",
  "site_id": "store-ops",
  "origin": "https://store-ops.syntheticindustry.ai",
  "records": [
    {
      "id": "bigcommerce-order-webhook-deactivated-orders-not-syncing",
      "type": "outcome",
      "title": "Get BigCommerce orders flowing again to the system that stopped receiving them",
      "description": "The receiving automation answers order notifications correctly under test, the webhooks are active again, and a list shows which orders missed the gap so you can catch them up.",
      "url": "/services/bigcommerce-order-webhook-deactivated-orders-not-syncing/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "bigcommerce",
        "webhooks",
        "orders"
      ],
      "related": [
        "inventory-shopify-stock-out-of-step-with-connected-system"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "inventory-shopify-stock-out-of-step-with-connected-system",
        "store-keep-order-inventory-sync-healthy",
        "guide-store-reconciling-orders-and-stock-between-systems",
        "guide-bigcommerce-webhook-retries-deactivation",
        "platform-bigcommerce",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "bigcommerce-order-webhook-deactivated-orders-not-syncing",
          "source": "/services/bigcommerce-order-webhook-deactivated-orders-not-syncing/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "bigcommerce-order-webhook-deactivated-orders-not-syncing",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/bigcommerce-order-webhook-deactivated-orders-not-syncing/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=bigcommerce-order-webhook-deactivated-orders-not-syncing&source=%2Fservices%2Fbigcommerce-order-webhook-deactivated-orders-not-syncing%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=bigcommerce-order-webhook-deactivated-orders-not-syncing&body=SI-Outcome%3A%20bigcommerce-order-webhook-deactivated-orders-not-syncing%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fbigcommerce-order-webhook-deactivated-orders-not-syncing%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "checkout-keep-test-order-passing-through-updates",
      "type": "recurring",
      "title": "Test your WooCommerce checkout on a copy before each monthly update window",
      "description": "Once a month, before your update window, we apply your pending updates to a store copy and run an agreed script of up to eight checkout cases before and after, then tell you whether to apply or hold.",
      "url": "/services/checkout-keep-test-order-passing-through-updates/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "woocommerce",
        "wordpress",
        "checkout",
        "staging"
      ],
      "related": [
        "store-recovery-woocommerce-after-failed-update"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "store-recovery-woocommerce-after-failed-update",
        "example-woocommerce-test-order-matrix",
        "guide-woocommerce-subscription-renewals-scheduler",
        "guide-woocommerce-update-test-order-script",
        "buyer-merchant-ops-store-without-developer"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "checkout-keep-test-order-passing-through-updates",
          "source": "/services/checkout-keep-test-order-passing-through-updates/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "checkout-keep-test-order-passing-through-updates",
          "SI-Mode": "subscribe",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/checkout-keep-test-order-passing-through-updates/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=checkout-keep-test-order-passing-through-updates&source=%2Fservices%2Fcheckout-keep-test-order-passing-through-updates%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=checkout-keep-test-order-passing-through-updates&body=SI-Outcome%3A%20checkout-keep-test-order-passing-through-updates%0ASI-Mode%3A%20subscribe%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fcheckout-keep-test-order-passing-through-updates%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "inventory-shopify-stock-out-of-step-with-connected-system",
      "type": "outcome",
      "title": "Bring Shopify stock levels back in line with the system you sync them with",
      "description": "For an agreed set of products at one location, Shopify stock matches your other system under a written rule, proved on a test store and a copy of the other system, with a test sale reducing both once.",
      "url": "/services/inventory-shopify-stock-out-of-step-with-connected-system/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "shopify",
        "inventory",
        "sync"
      ],
      "related": [
        "bigcommerce-order-webhook-deactivated-orders-not-syncing",
        "shopify-csv-import-merged-or-overwrote-products"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "bigcommerce-order-webhook-deactivated-orders-not-syncing",
        "store-keep-order-inventory-sync-healthy",
        "example-store-stock-reconciliation-sheet",
        "guide-shopify-inventory-locations-set-versus-adjust",
        "guide-store-reconciling-orders-and-stock-between-systems",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "inventory-shopify-stock-out-of-step-with-connected-system",
          "source": "/services/inventory-shopify-stock-out-of-step-with-connected-system/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "inventory-shopify-stock-out-of-step-with-connected-system",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/inventory-shopify-stock-out-of-step-with-connected-system/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=inventory-shopify-stock-out-of-step-with-connected-system&source=%2Fservices%2Finventory-shopify-stock-out-of-step-with-connected-system%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=inventory-shopify-stock-out-of-step-with-connected-system&body=SI-Outcome%3A%20inventory-shopify-stock-out-of-step-with-connected-system%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Finventory-shopify-stock-out-of-step-with-connected-system%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "magento-catalogue-changes-not-showing-indexers-cron",
      "type": "outcome",
      "title": "Fix Magento product, price or stock changes that do not appear on the storefront",
      "description": "On a copy of your Magento store, an edit to a test product shows on the storefront within an agreed time, and the indexer settings and scheduled jobs behind it are documented.",
      "url": "/services/magento-catalogue-changes-not-showing-indexers-cron/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "magento",
        "adobe-commerce",
        "cron",
        "indexers"
      ],
      "related": [],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "guide-magento-indexers-schedule-cron-triggers",
        "platform-magento",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "magento-catalogue-changes-not-showing-indexers-cron",
          "source": "/services/magento-catalogue-changes-not-showing-indexers-cron/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "magento-catalogue-changes-not-showing-indexers-cron",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/magento-catalogue-changes-not-showing-indexers-cron/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=magento-catalogue-changes-not-showing-indexers-cron&source=%2Fservices%2Fmagento-catalogue-changes-not-showing-indexers-cron%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=magento-catalogue-changes-not-showing-indexers-cron&body=SI-Outcome%3A%20magento-catalogue-changes-not-showing-indexers-cron%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fmagento-catalogue-changes-not-showing-indexers-cron%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "mapping-supplier-categories-to-store-categories",
      "type": "outcome",
      "title": "Map a supplier's category names onto your store categories, with no silent defaults",
      "description": "Every category value in a named supplier feed maps to exactly one of your store categories, or lands in a visible unmapped list. Nothing falls silently into a default category.",
      "url": "/services/mapping-supplier-categories-to-store-categories/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "product-feeds",
        "csv-files"
      ],
      "related": [],
      "provenance": [
        {
          "label": "Google's google_product_category help page says the attribute takes a predefined Google category as either a numeric ID or a full text path, not both, and that category lists are published as taxonomy files.",
          "url": "https://support.google.com/merchants/answer/6324436",
          "checked": "2026-10-11"
        },
        {
          "label": "The same page says the attribute is optional, and to use product_type for your own category labels when no Google category fits.",
          "url": "https://support.google.com/merchants/answer/6324436",
          "checked": "2026-10-11"
        }
      ],
      "incoming": [
        "guide-mapping-supplier-category-unmapped-queue",
        "platform-csv-files"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "mapping-supplier-categories-to-store-categories",
          "source": "/services/mapping-supplier-categories-to-store-categories/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "mapping-supplier-categories-to-store-categories",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/mapping-supplier-categories-to-store-categories/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=mapping-supplier-categories-to-store-categories&source=%2Fservices%2Fmapping-supplier-categories-to-store-categories%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=mapping-supplier-categories-to-store-categories&body=SI-Outcome%3A%20mapping-supplier-categories-to-store-categories%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fmapping-supplier-categories-to-store-categories%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "shopify-abandoned-checkout-emails-not-sending",
      "type": "outcome",
      "title": "Get Shopify abandoned checkout emails sending to the shoppers who qualify",
      "description": "Three test checkouts you run with your own email, each stopping before payment, give the expected result, a recovery email with a working link or none, and the settings behind them are written down.",
      "url": "/services/shopify-abandoned-checkout-emails-not-sending/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "shopify",
        "email",
        "abandoned-checkout"
      ],
      "related": [
        "shopify-discount-code-not-applying-as-intended"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "shopify-discount-code-not-applying-as-intended",
        "guide-shopify-abandoned-checkout-when-no-email",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "shopify-abandoned-checkout-emails-not-sending",
          "source": "/services/shopify-abandoned-checkout-emails-not-sending/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "shopify-abandoned-checkout-emails-not-sending",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/shopify-abandoned-checkout-emails-not-sending/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=shopify-abandoned-checkout-emails-not-sending&source=%2Fservices%2Fshopify-abandoned-checkout-emails-not-sending%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=shopify-abandoned-checkout-emails-not-sending&body=SI-Outcome%3A%20shopify-abandoned-checkout-emails-not-sending%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fshopify-abandoned-checkout-emails-not-sending%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "shopify-csv-import-merged-or-overwrote-products",
      "type": "outcome",
      "title": "Put products back after a Shopify CSV import overwrote them",
      "description": "A corrective product file and change report restore the fields and variants an import replaced or blanked, proved on a test store that first shows the same damage, before you touch the live one.",
      "url": "/services/shopify-csv-import-merged-or-overwrote-products/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "shopify",
        "csv-import"
      ],
      "related": [
        "store-catalogue-mapping-to-shopify-csv",
        "shopify-merchant-brand-identifier"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "inventory-shopify-stock-out-of-step-with-connected-system",
        "store-catalogue-mapping-to-shopify-csv",
        "example-shopify-product-csv-damage-before-after",
        "guide-shopify-csv-import-handle-overwrite-blank-cells",
        "buyer-store-owner-moving-platforms",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "shopify-csv-import-merged-or-overwrote-products",
          "source": "/services/shopify-csv-import-merged-or-overwrote-products/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "shopify-csv-import-merged-or-overwrote-products",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/shopify-csv-import-merged-or-overwrote-products/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=shopify-csv-import-merged-or-overwrote-products&source=%2Fservices%2Fshopify-csv-import-merged-or-overwrote-products%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=shopify-csv-import-merged-or-overwrote-products&body=SI-Outcome%3A%20shopify-csv-import-merged-or-overwrote-products%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fshopify-csv-import-merged-or-overwrote-products%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "shopify-discount-code-not-applying-as-intended",
      "type": "outcome",
      "title": "Make a Shopify discount code apply exactly as you intended",
      "description": "Each shopping basket on your list gets the discount, or the refusal, you specify on a test store, with the exact settings written down for you to apply.",
      "url": "/services/shopify-discount-code-not-applying-as-intended/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "shopify",
        "discounts"
      ],
      "related": [
        "shopify-abandoned-checkout-emails-not-sending"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "shopify-abandoned-checkout-emails-not-sending",
        "guide-shopify-discount-combination-rules",
        "buyer-merchant-ops-store-without-developer",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "shopify-discount-code-not-applying-as-intended",
          "source": "/services/shopify-discount-code-not-applying-as-intended/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "shopify-discount-code-not-applying-as-intended",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/shopify-discount-code-not-applying-as-intended/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=shopify-discount-code-not-applying-as-intended&source=%2Fservices%2Fshopify-discount-code-not-applying-as-intended%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=shopify-discount-code-not-applying-as-intended&body=SI-Outcome%3A%20shopify-discount-code-not-applying-as-intended%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fshopify-discount-code-not-applying-as-intended%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "shopify-merchant-brand-identifier",
      "type": "outcome",
      "title": "Fix Shopify products rejected for missing brand identifiers",
      "description": "The agreed products submit truthful brand and identifier fields and show no brand/identifier errors in the next Merchant Center item diagnostic; Google approval is not guaranteed.",
      "url": "/services/shopify-merchant-brand-identifier/",
      "updated": "2026-10-09",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "shopify",
        "google-merchant-center"
      ],
      "related": [],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales. Earlier unverified marketplace and community quotations are not used in this release."
        }
      ],
      "incoming": [
        "shopify-csv-import-merged-or-overwrote-products",
        "guide-merchant-brand-identifiers",
        "platform-shopify",
        "platform-google-merchant-center",
        "collection-merchant-center-flagged-products-diagnosis-order"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "shopify-merchant-brand-identifier",
          "source": "/services/shopify-merchant-brand-identifier/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "shopify-merchant-brand-identifier",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/shopify-merchant-brand-identifier/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=shopify-merchant-brand-identifier&source=%2Fservices%2Fshopify-merchant-brand-identifier%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=shopify-merchant-brand-identifier&body=SI-Outcome%3A%20shopify-merchant-brand-identifier%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fshopify-merchant-brand-identifier%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "shopify-product-tab-after-theme-update",
      "type": "outcome",
      "title": "Restore a Shopify product tab lost after a theme update",
      "description": "The agreed product-description tab opens and closes on a duplicated theme on phone and desktop while the underlying product text remains unchanged.",
      "url": "/services/shopify-product-tab-after-theme-update/",
      "updated": "2026-10-09",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "shopify",
        "liquid",
        "javascript"
      ],
      "related": [],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales. Earlier unverified marketplace and community quotations are not used in this release."
        }
      ],
      "incoming": [
        "shopify-uninstalled-review-app-residue",
        "buyer-ecommerce-owner-checkout",
        "guide-shopify-theme-update-regression",
        "platform-shopify"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "shopify-product-tab-after-theme-update",
          "source": "/services/shopify-product-tab-after-theme-update/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "shopify-product-tab-after-theme-update",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/shopify-product-tab-after-theme-update/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=shopify-product-tab-after-theme-update&source=%2Fservices%2Fshopify-product-tab-after-theme-update%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=shopify-product-tab-after-theme-update&body=SI-Outcome%3A%20shopify-product-tab-after-theme-update%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fshopify-product-tab-after-theme-update%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "shopify-uninstalled-review-app-residue",
      "type": "outcome",
      "title": "Remove leftover Shopify review-app code from one product template",
      "description": "On a duplicate theme the current review widget displays one copy of the expected review content, and retired app code no longer runs on the agreed product.",
      "url": "/services/shopify-uninstalled-review-app-residue/",
      "updated": "2026-10-09",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "shopify",
        "liquid"
      ],
      "related": [
        "shopify-product-tab-after-theme-update"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales. Earlier unverified marketplace and community quotations are not used in this release."
        }
      ],
      "incoming": [
        "guide-shopify-app-uninstall-cleanup",
        "platform-shopify"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "shopify-uninstalled-review-app-residue",
          "source": "/services/shopify-uninstalled-review-app-residue/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "shopify-uninstalled-review-app-residue",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/shopify-uninstalled-review-app-residue/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=shopify-uninstalled-review-app-residue&source=%2Fservices%2Fshopify-uninstalled-review-app-residue%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=shopify-uninstalled-review-app-residue&body=SI-Outcome%3A%20shopify-uninstalled-review-app-residue%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fshopify-uninstalled-review-app-residue%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "store-catalogue-mapping-to-shopify-csv",
      "type": "outcome",
      "title": "Turn a WooCommerce or Magento product export into a Shopify-ready import file",
      "description": "Your product export becomes a Shopify product file and a matching redirect file, proved by an import on a test store with counts and sampled values matching the source.",
      "url": "/services/store-catalogue-mapping-to-shopify-csv/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "shopify",
        "woocommerce",
        "magento",
        "csv-import"
      ],
      "related": [
        "shopify-csv-import-merged-or-overwrote-products",
        "woo-variable-product-variations-not-selectable"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "shopify-csv-import-merged-or-overwrote-products",
        "woo-variable-product-variations-not-selectable",
        "example-shopify-product-csv-damage-before-after",
        "guide-store-catalogue-move-option-variant-limits",
        "guide-store-redirects-and-launch-checks-after-replatform",
        "platform-magento",
        "buyer-store-owner-moving-platforms",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "store-catalogue-mapping-to-shopify-csv",
          "source": "/services/store-catalogue-mapping-to-shopify-csv/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "store-catalogue-mapping-to-shopify-csv",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/store-catalogue-mapping-to-shopify-csv/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=store-catalogue-mapping-to-shopify-csv&source=%2Fservices%2Fstore-catalogue-mapping-to-shopify-csv%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=store-catalogue-mapping-to-shopify-csv&body=SI-Outcome%3A%20store-catalogue-mapping-to-shopify-csv%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fstore-catalogue-mapping-to-shopify-csv%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "store-keep-order-inventory-sync-healthy",
      "type": "recurring",
      "title": "Check your store's orders and stock against the system they feed, every week",
      "description": "Each week we compare your store's orders and stock with the other system you sync to, and explain up to two causes of any difference a month, so drift is found in days, not after an oversell.",
      "url": "/services/store-keep-order-inventory-sync-healthy/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "shopify",
        "bigcommerce",
        "inventory",
        "orders",
        "sync"
      ],
      "related": [
        "inventory-shopify-stock-out-of-step-with-connected-system",
        "bigcommerce-order-webhook-deactivated-orders-not-syncing"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "example-store-stock-reconciliation-sheet",
        "guide-shopify-inventory-locations-set-versus-adjust",
        "guide-store-reconciling-orders-and-stock-between-systems",
        "guide-bigcommerce-webhook-retries-deactivation",
        "platform-bigcommerce",
        "buyer-merchant-ops-store-without-developer",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "store-keep-order-inventory-sync-healthy",
          "source": "/services/store-keep-order-inventory-sync-healthy/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "store-keep-order-inventory-sync-healthy",
          "SI-Mode": "subscribe",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/store-keep-order-inventory-sync-healthy/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=store-keep-order-inventory-sync-healthy&source=%2Fservices%2Fstore-keep-order-inventory-sync-healthy%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=store-keep-order-inventory-sync-healthy&body=SI-Outcome%3A%20store-keep-order-inventory-sync-healthy%0ASI-Mode%3A%20subscribe%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fstore-keep-order-inventory-sync-healthy%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "store-recovery-woocommerce-after-failed-update",
      "type": "composed",
      "title": "Recover a WooCommerce store after a failed update, to an agreed test-order pass",
      "description": "After a bad update broke several parts of your store, we agree a test-order checklist and work through the faults until the whole checklist passes on a copy, then hand over the fixes.",
      "url": "/services/store-recovery-woocommerce-after-failed-update/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "woocommerce",
        "wordpress",
        "php"
      ],
      "related": [
        "checkout-keep-test-order-passing-through-updates"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "checkout-keep-test-order-passing-through-updates",
        "example-woocommerce-test-order-matrix",
        "guide-woocommerce-update-test-order-script",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "store-recovery-woocommerce-after-failed-update",
          "source": "/services/store-recovery-woocommerce-after-failed-update/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "store-recovery-woocommerce-after-failed-update",
          "SI-Mode": "quote",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/store-recovery-woocommerce-after-failed-update/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=store-recovery-woocommerce-after-failed-update&source=%2Fservices%2Fstore-recovery-woocommerce-after-failed-update%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=store-recovery-woocommerce-after-failed-update&body=SI-Outcome%3A%20store-recovery-woocommerce-after-failed-update%0ASI-Mode%3A%20quote%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fstore-recovery-woocommerce-after-failed-update%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "stripe-memberstack-access-after-payment",
      "type": "outcome",
      "title": "Restore paid member access after Stripe takes a payment",
      "description": "One agreed test purchase activates exactly the intended membership tier on a test account; a failed payment activates nothing.",
      "url": "/services/stripe-memberstack-access-after-payment/",
      "updated": "2026-10-09",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "stripe",
        "memberstack",
        "webflow"
      ],
      "related": [],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales. Earlier unverified marketplace and community quotations are not used in this release."
        }
      ],
      "incoming": [
        "woo-orders-stuck-pending-after-payment",
        "platform-stripe",
        "guide-stripe-webhook-delivery",
        "guide-stripe-subscription-access",
        "guide-membership-builder-tools-what-they-cannot-do",
        "example-wordpress-members-access-matrix",
        "guide-wordpress-members-only-content-caching-and-data-routes"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "stripe-memberstack-access-after-payment",
          "source": "/services/stripe-memberstack-access-after-payment/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "stripe-memberstack-access-after-payment",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/stripe-memberstack-access-after-payment/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=stripe-memberstack-access-after-payment&source=%2Fservices%2Fstripe-memberstack-access-after-payment%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=stripe-memberstack-access-after-payment&body=SI-Outcome%3A%20stripe-memberstack-access-after-payment%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fstripe-memberstack-access-after-payment%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "woo-no-shipping-options-for-destination",
      "type": "outcome",
      "title": "Fix a WooCommerce checkout that offers no shipping for a country you serve",
      "description": "Each destination on your list shows the right shipping methods and costs at checkout on a store copy, and destinations you do not serve show none.",
      "url": "/services/woo-no-shipping-options-for-destination/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "woocommerce",
        "wordpress",
        "shipping-zones"
      ],
      "related": [
        "woocommerce-checkout-after-update",
        "woo-orders-stuck-pending-after-payment"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "checkout-keep-test-order-passing-through-updates",
        "store-recovery-woocommerce-after-failed-update",
        "guide-woocommerce-shipping-zone-order-and-postcodes",
        "buyer-merchant-ops-store-without-developer",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "woo-no-shipping-options-for-destination",
          "source": "/services/woo-no-shipping-options-for-destination/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "woo-no-shipping-options-for-destination",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/woo-no-shipping-options-for-destination/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=woo-no-shipping-options-for-destination&source=%2Fservices%2Fwoo-no-shipping-options-for-destination%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=woo-no-shipping-options-for-destination&body=SI-Outcome%3A%20woo-no-shipping-options-for-destination%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fwoo-no-shipping-options-for-destination%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "woo-orders-stuck-pending-after-payment",
      "type": "outcome",
      "title": "Fix WooCommerce orders that stay unpaid after the customer has paid",
      "description": "On a store copy, a successful test payment moves the order to the status you expect, the gateway reports the delivery as received, and a repeat delivery changes nothing twice.",
      "url": "/services/woo-orders-stuck-pending-after-payment/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "woocommerce",
        "wordpress",
        "stripe",
        "webhooks"
      ],
      "related": [
        "woocommerce-checkout-after-update",
        "stripe-memberstack-access-after-payment"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "checkout-keep-test-order-passing-through-updates",
        "store-recovery-woocommerce-after-failed-update",
        "woo-no-shipping-options-for-destination",
        "woo-subscription-renewals-not-processing",
        "guide-woocommerce-pending-payment-gateway-confirmation",
        "buyer-merchant-ops-store-without-developer",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "woo-orders-stuck-pending-after-payment",
          "source": "/services/woo-orders-stuck-pending-after-payment/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "woo-orders-stuck-pending-after-payment",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/woo-orders-stuck-pending-after-payment/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=woo-orders-stuck-pending-after-payment&source=%2Fservices%2Fwoo-orders-stuck-pending-after-payment%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=woo-orders-stuck-pending-after-payment&body=SI-Outcome%3A%20woo-orders-stuck-pending-after-payment%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fwoo-orders-stuck-pending-after-payment%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "woo-subscription-renewals-not-processing",
      "type": "outcome",
      "title": "Fix WooCommerce Subscriptions renewals that are late or never created",
      "description": "On a store copy, a test subscription due now gets its renewal order created inside an agreed window and its next renewal scheduled, with the scheduling cause named and documented.",
      "url": "/services/woo-subscription-renewals-not-processing/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "woocommerce",
        "woocommerce-subscriptions",
        "wordpress",
        "action-scheduler"
      ],
      "related": [
        "woo-orders-stuck-pending-after-payment",
        "woocommerce-checkout-after-update"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "guide-woocommerce-subscription-renewals-scheduler",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "woo-subscription-renewals-not-processing",
          "source": "/services/woo-subscription-renewals-not-processing/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "woo-subscription-renewals-not-processing",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/woo-subscription-renewals-not-processing/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=woo-subscription-renewals-not-processing&source=%2Fservices%2Fwoo-subscription-renewals-not-processing%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=woo-subscription-renewals-not-processing&body=SI-Outcome%3A%20woo-subscription-renewals-not-processing%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fwoo-subscription-renewals-not-processing%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "woo-variable-product-variations-not-selectable",
      "type": "outcome",
      "title": "Make a WooCommerce variable product sell every size and colour again",
      "description": "The agreed variable product shows each valid option combination on a store copy, with the right price and stock, and each one adds to the cart as the matching variation.",
      "url": "/services/woo-variable-product-variations-not-selectable/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "woocommerce",
        "wordpress",
        "csv-import"
      ],
      "related": [
        "woocommerce-checkout-after-update",
        "store-catalogue-mapping-to-shopify-csv"
      ],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales."
        }
      ],
      "incoming": [
        "store-catalogue-mapping-to-shopify-csv",
        "store-recovery-woocommerce-after-failed-update",
        "guide-woocommerce-variation-attributes-and-any",
        "collection-store-checkout-order-flow-diagnosis",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "woo-variable-product-variations-not-selectable",
          "source": "/services/woo-variable-product-variations-not-selectable/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "woo-variable-product-variations-not-selectable",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/woo-variable-product-variations-not-selectable/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=woo-variable-product-variations-not-selectable&source=%2Fservices%2Fwoo-variable-product-variations-not-selectable%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=woo-variable-product-variations-not-selectable&body=SI-Outcome%3A%20woo-variable-product-variations-not-selectable%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fwoo-variable-product-variations-not-selectable%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "woocommerce-checkout-after-update",
      "type": "outcome",
      "title": "Fix a WooCommerce checkout that broke after an update",
      "description": "Find and fix the one fault that stops customers completing an order after an update, proved with a test order on a copy of your store.",
      "url": "/services/woocommerce-checkout-after-update/",
      "updated": "2026-10-09",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "woocommerce",
        "wordpress",
        "php",
        "wordpress-woocommerce"
      ],
      "related": [],
      "provenance": [
        {
          "label": "Commercial hypothesis for this bounded outcome, not verified buyer demand or a tested price. The 9 October direction permits reasonable offers without inventing prior sales. Earlier unverified marketplace and community quotations are not used in this release."
        }
      ],
      "incoming": [
        "checkout-keep-test-order-passing-through-updates",
        "store-recovery-woocommerce-after-failed-update",
        "woo-no-shipping-options-for-destination",
        "woo-orders-stuck-pending-after-payment",
        "woo-subscription-renewals-not-processing",
        "woo-variable-product-variations-not-selectable",
        "buyer-ecommerce-owner-checkout",
        "platform-wordpress-woocommerce",
        "guide-woocommerce-checkout-conflicts",
        "guide-woocommerce-pending-payment-gateway-confirmation",
        "guide-woocommerce-update-test-order-script"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "woocommerce-checkout-after-update",
          "source": "/services/woocommerce-checkout-after-update/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "woocommerce-checkout-after-update",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/woocommerce-checkout-after-update/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=woocommerce-checkout-after-update&source=%2Fservices%2Fwoocommerce-checkout-after-update%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=woocommerce-checkout-after-update&body=SI-Outcome%3A%20woocommerce-checkout-after-update%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fwoocommerce-checkout-after-update%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "xml-supplier-feed-parse-errors-import",
      "type": "outcome",
      "title": "Read every item in a supplier XML feed, and reject a broken file cleanly",
      "description": "A named supplier XML sample imports every well-formed item, with namespaces, CDATA and escapes read correctly; a broken copy is rejected with its line and column and changes nothing.",
      "url": "/services/xml-supplier-feed-parse-errors-import/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "xml",
        "xml-feeds"
      ],
      "related": [],
      "provenance": [
        {
          "label": "The W3C XML 1.0 specification says a processor must report a well-formedness violation as a fatal error and must not continue passing character data and structure information to the application as normal.",
          "url": "https://www.w3.org/TR/xml/",
          "checked": "2026-10-11"
        },
        {
          "label": "It says literal < and & may appear only as markup, or inside comments, processing instructions or CDATA sections, and must otherwise be escaped; and that end-tag names must match start-tag names exactly, with no case folding.",
          "url": "https://www.w3.org/TR/xml/",
          "checked": "2026-10-11"
        },
        {
          "label": "Python's xml documentation warns that attacker-controlled XML can cause denial of service, and names entity-expansion attacks such as billion laughs and quadratic blowup.",
          "url": "https://docs.python.org/3/library/xml.html",
          "checked": "2026-10-11"
        }
      ],
      "incoming": [
        "example-xml-feed-first-error-cases",
        "platform-xml-feeds",
        "buyer-feed-operations-manager-supplier-file-delivery"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "xml-supplier-feed-parse-errors-import",
          "source": "/services/xml-supplier-feed-parse-errors-import/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "xml-supplier-feed-parse-errors-import",
          "SI-Mode": "request",
          "SI-Page": "https://store-ops.syntheticindustry.ai/services/xml-supplier-feed-parse-errors-import/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=xml-supplier-feed-parse-errors-import&source=%2Fservices%2Fxml-supplier-feed-parse-errors-import%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=xml-supplier-feed-parse-errors-import&body=SI-Outcome%3A%20xml-supplier-feed-parse-errors-import%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fservices%2Fxml-supplier-feed-parse-errors-import%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "buyer-ecommerce-owner-checkout",
      "type": "buyer",
      "title": "For an ecommerce owner: restore the buying journey without experimenting on live orders",
      "description": "Specify the checkout that fails, preserve payment safety and judge a repair by a completed synthetic order rather than a screenshot.",
      "slug": "ecommerce-owner-checkout",
      "url": "/buyers/ecommerce-owner-checkout/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "WooCommerce: conflict testing",
          "url": "https://woocommerce.com/document/how-to-test-for-conflicts/",
          "checked": "2026-10-10",
          "claims": [
            "Backup and staging protect the store during conflict testing."
          ]
        },
        {
          "label": "Shopify: theme updates",
          "url": "https://help.shopify.com/en/manual/online-store/themes/managing-themes/updating-themes",
          "checked": "2026-10-10",
          "claims": [
            "Updated themes are drafts that need review before publication."
          ]
        }
      ],
      "related": [
        "woocommerce-checkout-after-update",
        "guide-woocommerce-checkout-conflicts",
        "shopify-product-tab-after-theme-update",
        "platform-shopify",
        "guide-merchant-brand-identifiers"
      ],
      "sections": [
        {
          "heading": "Tell us where the buyer stops",
          "body": [
            "Describe the product, device, shipping choice and payment method involved. A missing product tab, a missing shipping rate and a rejected payment are different failures. Say whether every shopper is affected or only one combination. Do not estimate lost sales from unmeasured traffic or a guessed conversion rate."
          ],
          "items": [
            "Keep public screenshots and a redacted error.",
            "Record the update or app change before the failure.",
            "Do not send real order records or customer payment details."
          ]
        },
        {
          "heading": "A store copy needs explicit isolation",
          "body": [
            "A staging copy can inherit live gateways, emails and fulfilment hooks. Agree who disables external effects and supplies synthetic products, customers and test payment settings. The objective is to reproduce the real buying journey safely, not generate a live sale during diagnosis."
          ],
          "items": [
            "Name who owns the payment and store accounts.",
            "Keep a restore point and known prior theme or plugin state.",
            "Do not deactivate essential live checkout components without an authorised plan."
          ]
        },
        {
          "heading": "What the owner should inspect",
          "body": [
            "For a checkout repair, inspect the same agreed product-to-confirmation journey, expected totals, order creation and status. For a product-page repair, inspect the affected feature plus an unaffected product. The handover should include cause, evidence, changed settings and reversal. An isolated successful test does not establish site-wide conversion uplift."
          ],
          "items": [
            "Accept the specific result, not an unexplained green badge.",
            "Approve the live route separately; no account control transfers through an enquiry."
          ]
        },
        {
          "heading": "Start with the smallest useful request",
          "body": [
            "Send the platform, broken step, timing and redacted symptom. Scope and price are confirmed before private access or work. If several business paths are broken, ask for a coordinated scope rather than buying unrelated fixes that cannot be safely tested together."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-merchant-brand-identifiers",
        "guide-woocommerce-checkout-conflicts",
        "buyer-merchant-ops-store-without-developer"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/buyers/ecommerce-owner-checkout/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/buyers/ecommerce-owner-checkout/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fbuyers%2Fecommerce-owner-checkout%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fbuyers%2Fecommerce-owner-checkout%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-merchant-brand-identifiers",
      "type": "guide",
      "title": "Shopify product rejected for brand identifiers: use the actual product facts",
      "description": "Differentiate a missing brand from identifier requirements and avoid inventing values simply to clear a Merchant Center warning.",
      "slug": "merchant-brand-identifiers",
      "url": "/guides/merchant-brand-identifiers/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "Google Merchant Center: brand attribute",
          "url": "https://support.google.com/merchants/answer/6324351?hl=en",
          "checked": "2026-10-10",
          "claims": [
            "Use an accurate identifiable brand or manufacturer.",
            "Do not guess a brand when it is unknown.",
            "Custom or private-label goods have specific guidance; custom goods are not automatically exempt from identifiers."
          ]
        }
      ],
      "related": [
        "shopify-merchant-brand-identifier",
        "platform-shopify",
        "buyer-ecommerce-owner-checkout"
      ],
      "sections": [
        {
          "heading": "Read the exact rejection",
          "body": [
            "Record the affected channel, item and attribute named in the diagnostic. A missing brand, missing GTIN and invalid manufacturer part number are different issues. Check the actual product and supplier information rather than copying one generic value across the catalogue."
          ],
          "items": [
            "Keep a redacted rejection message and the named affected product.",
            "Compare product facts with the submitted feed value.",
            "Do not invent a GTIN, manufacturer or brand to silence the warning."
          ]
        },
        {
          "heading": "Apply the relevant product rule",
          "body": [
            "Google's brand guidance requires an accurate brand or maker where identifiable. Custom and private-label goods have specific rules, including shop-name branding in certain cases; custom goods are not automatically exempt. Goods with no identifiable brand can have different treatment. Follow the current attribute guidance for the actual item rather than marking every product identifier_exists false."
          ],
          "items": [
            "Use the recognised maker for a third-party compatible product.",
            "Review other required identifiers separately.",
            "Do not alter product images to fabricate branding evidence."
          ]
        },
        {
          "heading": "Check the mapping before resubmission",
          "body": [
            "Identify where the channel gets its brand and identifier values: the source product fields, a feed mapping or an app transformation. Correct the authoritative source or agreed mapping and inspect the submitted result. A correct Shopify display field does not guarantee the feed sent the same value."
          ],
          "items": [
            "Limit changes to the agreed product set.",
            "Preserve a before/after field record with public or synthetic facts.",
            "Account-holder authority is required for channel changes and submission."
          ]
        },
        {
          "heading": "Acceptance boundary",
          "body": [
            "The bounded outcome should name which products and rejection reasons were corrected and the channel result used to verify them. It does not promise rankings, advertising approval for unrelated policy issues or increased sales. Send the redacted diagnostic and product facts initially, not merchant credentials."
          ],
          "items": []
        }
      ],
      "incoming": [
        "buyer-ecommerce-owner-checkout"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/merchant-brand-identifiers/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/merchant-brand-identifiers/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fmerchant-brand-identifiers%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fmerchant-brand-identifiers%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-shopify-theme-update-regression",
      "type": "guide",
      "title": "Restore a custom product tab after a Shopify theme update",
      "description": "Compare the updated draft with the previous theme and distinguish editor settings from incompatible custom code.",
      "slug": "shopify-theme-update-regression",
      "url": "/guides/shopify-theme-update-regression/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "Shopify: updating themes",
          "url": "https://help.shopify.com/en/manual/online-store/themes/managing-themes/updating-themes",
          "checked": "2026-10-10",
          "claims": [
            "Updates create a draft; editor customisations carry over.",
            "Custom code transfers only when compatible; review custom CSS and app compatibility before publishing."
          ]
        }
      ],
      "related": [
        "platform-shopify",
        "shopify-product-tab-after-theme-update",
        "guide-shopify-app-uninstall-cleanup"
      ],
      "sections": [
        {
          "heading": "Name the exact missing feature",
          "body": [
            "Identify one product, its assigned template and the tab's expected content. Was it configured in the theme editor, inserted by an app or added through a code change? Keep the previous theme as the reference and record the update version. A missing tab can be a template assignment or settings problem, not necessarily missing code."
          ],
          "items": [
            "Capture old and new behaviour using public content only.",
            "Check whether the tab is absent everywhere or on one template.",
            "Do not publish repeated experimental themes on the live storefront."
          ]
        },
        {
          "heading": "Read the update's carryover status",
          "body": [
            "Shopify theme updates create a separate draft. Editor customisations can carry over, but custom and app-generated code transfer only if compatible. Review any notice that code edits were or were not included. Compare the specific template, section or snippet with the old theme rather than copying the entire old codebase over the update."
          ],
          "items": [
            "Inspect app blocks and theme settings on the draft.",
            "Recheck CSS against the updated theme's selectors.",
            "Preserve necessary new-theme fixes instead of blindly reverting all files."
          ]
        },
        {
          "heading": "Define a useful acceptance test",
          "body": [
            "On the draft, the named product shows the expected tab and content, the tab opens with keyboard and pointer input, and the agreed mobile layout remains usable. Also check an unaffected product template and its add-to-cart path. This proves the bounded storefront change, not sales uplift or every checkout path."
          ],
          "items": [
            "Record changed files or settings and screenshots of the agreed states.",
            "Name any app dependency or content that was not included.",
            "Keep a clear route back to the prior published theme."
          ]
        },
        {
          "heading": "Before requesting work",
          "body": [
            "Send the theme names and versions, product/template affected and a redacted description of the lost feature. The account holder controls publication and grants only agreed access after scope. A missing tab does not require passwords or private customer exports in an enquiry."
          ],
          "items": []
        }
      ],
      "platforms": [
        "shopify"
      ],
      "incoming": [
        "guide-shopify-app-uninstall-cleanup",
        "platform-shopify"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/shopify-theme-update-regression/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/shopify-theme-update-regression/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fshopify-theme-update-regression%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fshopify-theme-update-regression%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-shopify-app-uninstall-cleanup",
      "type": "guide",
      "title": "Uninstalled a Shopify review app? Check code, data and billing separately",
      "description": "Remove a leftover storefront widget without assuming app removal preserved reviews or ended an external subscription.",
      "slug": "shopify-app-uninstall-cleanup",
      "url": "/guides/shopify-app-uninstall-cleanup/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "Shopify: uninstalling apps",
          "url": "https://help.shopify.com/en/manual/apps/uninstalling-apps",
          "checked": "2026-10-10",
          "claims": [
            "Apps can leave theme code after uninstall.",
            "Separately billed subscriptions are not necessarily cancelled by Shopify uninstall.",
            "App developers can provide cleanup and billing guidance."
          ]
        }
      ],
      "related": [
        "platform-shopify",
        "shopify-uninstalled-review-app-residue",
        "guide-shopify-theme-update-regression"
      ],
      "sections": [
        {
          "heading": "Three checks, not one uninstall button",
          "body": [
            "Removing an app from Shopify, removing its storefront code and preserving its review data are different tasks. Shopify warns that app code may remain after uninstall. Separately billed subscriptions may also require cancellation with the provider. Do not interpret an absent app listing as proof that every widget, stored review or external charge has been handled."
          ],
          "items": [
            "Identify the app and its own cleanup instructions.",
            "Record which review data or authorised export must be retained.",
            "Ask the account holder to check external billing directly."
          ]
        },
        {
          "heading": "Compare a theme copy",
          "body": [
            "Work on an unpublished theme copy and locate the app's specific snippets, includes, blocks or assets. A name that resembles the app is a clue, not permission to delete everything matching it. Templates can share code with other features. Keep the baseline theme and changed-file list so the edit can be reversed."
          ],
          "items": [
            "Check the product pages where the residue appears.",
            "Compare console or network errors without exposing private account information.",
            "Do not upload private review exports to an agent workspace."
          ]
        },
        {
          "heading": "Acceptance is more than hiding the widget",
          "body": [
            "The residual widget or unwanted reference should disappear on the agreed pages, preserved review content should remain available through the agreed route, and unrelated product-page behaviour should still work. If data recovery requires vendor access, an absent export or another subscription, stop and re-scope rather than claim the reviews are saved."
          ],
          "items": [
            "Test one affected and one unaffected product template.",
            "Record what was removed and what was retained.",
            "Keep vendor billing and live-theme publication outside an unauthorised test."
          ]
        },
        {
          "heading": "Safe enquiry",
          "body": [
            "Send the app name, public affected page, uninstall date and whether the needed export already exists. Do not send review records, credentials or an access invitation initially. We can scope the cleanup from the symptoms and agree the private route later."
          ],
          "items": []
        }
      ],
      "platforms": [
        "shopify"
      ],
      "incoming": [
        "guide-shopify-theme-update-regression",
        "platform-shopify"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/shopify-app-uninstall-cleanup/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/shopify-app-uninstall-cleanup/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fshopify-app-uninstall-cleanup%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fshopify-app-uninstall-cleanup%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "platform-stripe",
      "type": "platform",
      "title": "Stripe integrations: payment, subscription and access are different states",
      "description": "Understand asynchronous payment events, reliable subscription access and the boundaries of a safe test-mode integration.",
      "slug": "stripe",
      "url": "/platforms/stripe/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "Stripe: webhooks",
          "url": "https://docs.stripe.com/webhooks",
          "checked": "2026-10-10",
          "claims": [
            "Webhook signature verification needs the original request body.",
            "Events can be duplicated and delivered out of order."
          ]
        },
        {
          "label": "Stripe: subscription webhooks",
          "url": "https://docs.stripe.com/billing/subscriptions/webhooks",
          "checked": "2026-10-10",
          "claims": [
            "Subscription activity is asynchronous.",
            "invoice.paid and subscription status inform provisioning; failed payments and cancellation need explicit handling."
          ]
        }
      ],
      "related": [
        "guide-stripe-webhook-delivery",
        "guide-stripe-subscription-access",
        "stripe-memberstack-access-after-payment"
      ],
      "sections": [
        {
          "heading": "A checkout redirect is not your access ledger",
          "body": [
            "The browser returning to a success page is a user-interface event. Subscription renewals, payment failures and cancellation happen later, without that browser session. An application needs an authenticated mapping between its user and Stripe customer, verified server-side events and an owner-approved access policy."
          ],
          "items": [
            "Payment state: whether an invoice or payment succeeded.",
            "Subscription state: whether the subscription is active, trialing, past_due, canceled or another supported state.",
            "Application access: the features that your product allows under your agreed rules."
          ]
        },
        {
          "heading": "Reliable event handling",
          "body": [
            "Stripe does not guarantee event order and can deliver an event more than once. Verify its signature using the unmodified request body, recognise events already processed and make business updates safe to repeat. A successful HTTP acknowledgement should not mask a lost update: if work is deferred, record it durably first."
          ],
          "items": [
            "Keep test and live destinations and signing secrets separate.",
            "Record event IDs and processing results without logging full customer payloads.",
            "Investigate the destination response before blaming checkout configuration."
          ]
        },
        {
          "heading": "Choose the actual outcome",
          "body": [
            "Adding plans to an app that has no subscription lifecycle is different from repairing paid-member access in an existing membership product. Custom card collection, marketplace payouts, tax advice and migrating an old subscriber base are separate scopes. A refund or dispute policy also needs explicit product-owner decisions; this guide does not authorise financial actions."
          ],
          "items": [
            "First prove purchase, renewal and cancellation using synthetic test accounts.",
            "Agree whether a failed renewal has a grace period; do not infer that from one event name."
          ]
        },
        {
          "heading": "Safe first contact",
          "body": [
            "Describe the platform, expected access rule and redacted event type or failure response. Do not send card data, secret keys, customer lists or full event payloads. A written scope and safe test route precede any private work or live change; the offer is enquiry-led, not an automatic payment instruction."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-stripe-webhook-delivery",
        "guide-stripe-subscription-access",
        "guide-woocommerce-pending-payment-gateway-confirmation",
        "guide-woocommerce-subscription-renewals-scheduler"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/platforms/stripe/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/platforms/stripe/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fplatforms%2Fstripe%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fplatforms%2Fstripe%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-stripe-webhook-delivery",
      "type": "guide",
      "title": "Stripe webhook not updating your app? Separate delivery from processing",
      "description": "Check the destination response, raw-body signature verification and durable processing before replaying payment events.",
      "slug": "stripe-webhook-delivery",
      "url": "/guides/stripe-webhook-delivery/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "Stripe: webhook delivery and verification",
          "url": "https://docs.stripe.com/webhooks",
          "checked": "2026-10-10",
          "claims": [
            "Stripe documents delivery response diagnostics and retries.",
            "Signature verification requires the raw request body and the correct endpoint secret.",
            "Duplicates and unordered delivery must be handled."
          ]
        }
      ],
      "related": [
        "platform-stripe",
        "guide-stripe-subscription-access",
        "stripe-memberstack-access-after-payment"
      ],
      "sections": [
        {
          "heading": "Locate the failure boundary",
          "body": [
            "In the account holder's Stripe event-destination view, identify one event and its delivery attempt. First distinguish no subscribed event, failed HTTP delivery and successful delivery followed by an incorrect application update. The last case needs application processing evidence; repeatedly changing the destination URL will not explain it."
          ],
          "items": [
            "Confirm test versus live mode and the intended destination.",
            "Compare the subscribed event type with the event your application expects.",
            "Keep a redacted response status and event ID; do not export customer payloads for an enquiry."
          ]
        },
        {
          "heading": "When signature verification fails",
          "body": [
            "Stripe's verification needs the original request-body bytes, its signature header and the correct signing secret. Middleware that parses and reserialises JSON can change those bytes. A CLI-forwarded test event and a registered destination can have different signing secrets. The account holder should verify which secret is configured through approved secret settings, not paste it into a conversation."
          ],
          "items": [
            "Do not disable verification to make deliveries pass.",
            "Check body-handling and environment configuration on a synthetic test route.",
            "Treat a valid signature as origin verification, not as authorisation for every business action."
          ]
        },
        {
          "heading": "A successful response can still lose work",
          "body": [
            "If the handler acknowledges before recording its update or queued work, a later crash can leave Stripe reporting delivery success while access is stale. Design for a durable handoff and idempotent processing. Conversely, a timeout after a completed action can lead to delivery retries; simply processing everything again can duplicate side effects."
          ],
          "items": [
            "Recognise already-processed event IDs and use safe business-operation identity.",
            "Retrieve current relevant Stripe state rather than assuming event arrival order is chronological.",
            "Log minimal processing outcomes separately from HTTP delivery outcomes."
          ]
        },
        {
          "heading": "Replay only with a defined purpose",
          "body": [
            "Replaying a live event can repeat emails, provisioning or other financial side effects. First test duplicate handling with synthetic events and an isolated account. Then an authorised operator can agree which live events need recovery and how completion will be reconciled. Never replay the entire event history merely because one membership is wrong."
          ],
          "items": []
        }
      ],
      "platforms": [
        "stripe",
        "supabase"
      ],
      "incoming": [
        "platform-stripe",
        "guide-stripe-subscription-access",
        "guide-woocommerce-pending-payment-gateway-confirmation",
        "guide-bigcommerce-webhook-retries-deactivation"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/stripe-webhook-delivery/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/stripe-webhook-delivery/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fstripe-webhook-delivery%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fstripe-webhook-delivery%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-stripe-subscription-access",
      "type": "guide",
      "title": "Keep application access correct when a Stripe subscription changes",
      "description": "Map purchase, renewal, failed payment and cancellation to an explicit access policy instead of trusting a success page.",
      "slug": "stripe-subscription-access",
      "url": "/guides/stripe-subscription-access/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "Stripe: subscription webhooks",
          "url": "https://docs.stripe.com/billing/subscriptions/webhooks",
          "checked": "2026-10-10",
          "claims": [
            "customer.subscription.created can be incomplete.",
            "invoice.paid should be considered with current subscription status for access.",
            "past_due handling depends on subscription settings; canceled and unpaid require access handling.",
            "customer.subscription.deleted indicates the subscription ended."
          ]
        }
      ],
      "related": [
        "platform-stripe",
        "guide-stripe-webhook-delivery",
        "stripe-memberstack-access-after-payment"
      ],
      "sections": [
        {
          "heading": "Write the policy before implementing it",
          "body": [
            "Define the permitted features for each plan and what happens during trial, initial payment requiring action, renewal failure, grace period and cancellation. A newly created subscription can be incomplete. Granting access solely because a subscription object exists can unlock a product before the required payment or authentication is complete."
          ],
          "items": [
            "Map stable application user IDs to Stripe customers; email text alone is a fragile identity rule.",
            "Name the price IDs and plan permissions in test mode.",
            "State whether cancel-at-period-end retains access until the paid period ends."
          ]
        },
        {
          "heading": "Read current state, not just the event name",
          "body": [
            "Stripe documents using invoice.paid together with the relevant subscription status when extending access. A failed renewal is not automatically identical to permanent cancellation: retry and final-status settings affect what happens next. Your product's grace policy must be explicit rather than inferred from the latest-arriving webhook."
          ],
          "items": [
            "Handle customer.subscription.updated when rules or status change.",
            "Handle ended subscriptions and the owner-approved unpaid/canceled behaviour.",
            "Do not treat paused payment collection and a paused subscription as interchangeable."
          ]
        },
        {
          "heading": "Check both permitted and denied behaviour",
          "body": [
            "Testing only the successful purchase leaves the dangerous cases unexamined. Use disposable accounts and synthetic data to test renewal, payment requiring action, failed renewal, scheduled cancellation and actual subscription end. Inspect protected server routes as well as visible screens; hiding a button does not enforce access."
          ],
          "items": [
            "An unrelated account must never inherit another customer's plan.",
            "Replay a processed event and check that access and subscription rows are not duplicated.",
            "Deliver older events after newer ones and verify the agreed current state remains authoritative."
          ]
        },
        {
          "heading": "What to send for an access repair",
          "body": [
            "Describe expected versus observed access and the redacted event type, mode and response. State the membership platform and whether the issue affects purchase, renewal or cancellation. Do not send member identities, card data or secret keys. Recovery of real customers and any financial action require separately agreed authority."
          ],
          "items": []
        }
      ],
      "platforms": [
        "stripe",
        "supabase"
      ],
      "incoming": [
        "platform-stripe",
        "guide-stripe-webhook-delivery"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/stripe-subscription-access/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/stripe-subscription-access/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fstripe-subscription-access%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fstripe-subscription-access%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "platform-wordpress-woocommerce",
      "type": "platform",
      "title": "WordPress and WooCommerce repair: protect the live store while finding the conflict",
      "description": "Differentiate a critical error from a checkout regression and test an isolated cause without experimenting on live orders.",
      "slug": "wordpress-woocommerce",
      "url": "/platforms/wordpress-woocommerce/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "WordPress: debugging",
          "url": "https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/",
          "checked": "2026-10-10",
          "claims": [
            "Debug logging and display can be separated; debug tools are intended for development or staging."
          ]
        },
        {
          "label": "WooCommerce: conflict testing",
          "url": "https://woocommerce.com/document/how-to-test-for-conflicts/",
          "checked": "2026-10-10",
          "claims": [
            "Backup and staging precede theme/plugin conflict isolation.",
            "Must-use plugins and drop-ins can remain active during ordinary plugin isolation."
          ]
        }
      ],
      "related": [
        "guide-woocommerce-checkout-conflicts",
        "woocommerce-checkout-after-update"
      ],
      "sections": [
        {
          "heading": "Start with what the visitor cannot do",
          "body": [
            "A critical error or HTTP 500 concerns the site's execution. A store that loads but cannot complete checkout has a different failure and acceptance test. Write the exact visitor sequence, affected product or page, first observed time and preceding update before changing plugins."
          ],
          "items": [
            "Critical error: inspect existing application and host logs for a first relevant fatal error.",
            "Checkout failure: record whether failure occurs at cart, address, shipping, payment or order confirmation.",
            "Keep customer details and payment information out of screenshots and enquiry logs."
          ]
        },
        {
          "heading": "A staging copy is not automatically harmless",
          "body": [
            "WooCommerce recommends a staging copy and backups for conflict testing. A clone can still contain live payment, email or integration settings. Agree an isolated test route, synthetic orders and disabled external effects before testing; merely changing the hostname does not make a copy safe."
          ],
          "items": [
            "Keep a known restore point and name who can restore it.",
            "Use a test payment configuration approved by the account holder.",
            "Do not copy real customer records into an agent's workspace."
          ]
        },
        {
          "heading": "Find a cause, not a lucky combination",
          "body": [
            "Compare the theme and plugin combinations systematically and repeat the same failing sequence. Host-managed must-use plugins, drop-ins and caches can survive ordinary deactivation. Record each combination and result; if re-enabling a component restores the failure, that is more useful than leaving everything disabled."
          ],
          "items": [
            "Do not remove essential checkout capabilities simply to obtain a passing demonstration.",
            "After a fix, check an unaffected path as well as the original regression."
          ]
        },
        {
          "heading": "Choose an accountable repair",
          "body": [
            "Request the named broken flow with a redacted error and change history. The scope should state included components, exclusions, test-order evidence, reversal and who approves a live change. This is a newly offered service catalogue, not evidence of previous customer deliveries or guaranteed conversion improvement."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-woocommerce-checkout-conflicts",
        "example-woocommerce-test-order-matrix",
        "guide-store-catalogue-move-option-variant-limits",
        "guide-woocommerce-variation-attributes-and-any",
        "guide-woocommerce-shipping-zone-order-and-postcodes",
        "guide-woocommerce-pending-payment-gateway-confirmation",
        "guide-woocommerce-subscription-renewals-scheduler",
        "guide-woocommerce-update-test-order-script"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/platforms/wordpress-woocommerce/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/platforms/wordpress-woocommerce/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fplatforms%2Fwordpress-woocommerce%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fplatforms%2Fwordpress-woocommerce%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-woocommerce-checkout-conflicts",
      "type": "guide",
      "title": "Diagnose WooCommerce checkout conflicts after an update",
      "description": "Isolate the failing theme or plugin on staging and prove the same product, shipping and test-payment journey works again.",
      "slug": "woocommerce-checkout-conflicts",
      "url": "/guides/woocommerce-checkout-conflicts/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "WooCommerce: conflict testing",
          "url": "https://woocommerce.com/document/how-to-test-for-conflicts/",
          "checked": "2026-10-10",
          "claims": [
            "Backups and a staging copy are recommended before conflict tests.",
            "Testing a standard theme and isolating plugins helps locate conflicts.",
            "Must-use plugins, drop-ins and caching can affect the result."
          ]
        }
      ],
      "related": [
        "platform-wordpress-woocommerce",
        "woocommerce-checkout-after-update",
        "buyer-ecommerce-owner-checkout"
      ],
      "sections": [
        {
          "heading": "Define the failing checkout",
          "body": [
            "Record the product, quantity, address category, shipping option and payment method used when failure occurs. Distinguish missing rates, a payment-widget error, rejected payment and an order that exists but shows an unexpected status. Each demands different evidence; 'checkout broken' is too broad for acceptance."
          ],
          "items": [
            "Use synthetic customer details and a test payment method.",
            "Record the visible error and any redacted application error.",
            "Note whether the issue affects every checkout or one product, country or method."
          ]
        },
        {
          "heading": "Prepare the isolated test",
          "body": [
            "WooCommerce's conflict guide starts with backup and staging. The account holder should ensure the copy cannot send real order emails, collect live payment or update a live fulfilment system. Keep the current baseline so a theme or plugin comparison can be reversed. Wholesale live updates or deactivation are not safe diagnostic shortcuts."
          ],
          "items": [
            "Confirm which payment and shipping extensions are needed to reproduce this checkout.",
            "Record WordPress, WooCommerce, theme and relevant plugin versions.",
            "Understand whether the store uses a block or classic checkout before changing its presentation."
          ]
        },
        {
          "heading": "Test one variable at a time",
          "body": [
            "Try an appropriate standard theme on the copy, then isolate nonessential plugins while retaining WooCommerce and the extensions necessary for the test. Repeat the same product-and-payment sequence. Re-enable components individually and record when the error returns. Check must-use plugins, drop-ins and caching if ordinary isolation does not explain it."
          ],
          "items": [
            "A passing test after removing the required shipping or payment method is not the same test.",
            "Do not assume a stale cached page proves the fix failed or passed."
          ]
        },
        {
          "heading": "What a useful repair handover contains",
          "body": [
            "Keep the failing and passing synthetic order journey, cause, changed files or settings and an independently reviewed reversal plan. Check that the agreed order is created once with expected totals and status; do not call a payment-page screenshot completed checkout. Real transactions and production publication remain separate authorised steps."
          ],
          "items": []
        }
      ],
      "platforms": [
        "wordpress-woocommerce"
      ],
      "incoming": [
        "buyer-ecommerce-owner-checkout",
        "platform-wordpress-woocommerce",
        "guide-woocommerce-shipping-zone-order-and-postcodes",
        "guide-woocommerce-update-test-order-script"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/woocommerce-checkout-conflicts/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/woocommerce-checkout-conflicts/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fwoocommerce-checkout-conflicts%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fwoocommerce-checkout-conflicts%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "platform-shopify",
      "type": "platform",
      "title": "Shopify theme and app changes: preserve storefront behaviour, not just appearance",
      "description": "Understand theme-update carryover, app-code remnants and the evidence needed to repair an existing storefront safely.",
      "slug": "shopify",
      "url": "/platforms/shopify/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "Shopify: theme updates",
          "url": "https://help.shopify.com/en/manual/online-store/themes/managing-themes/updating-themes",
          "checked": "2026-10-10",
          "claims": [
            "Theme updates create a draft before publication.",
            "Custom or app-generated code transfers only when compatible.",
            "Custom CSS and app compatibility should be rechecked."
          ]
        },
        {
          "label": "Shopify: uninstalling apps",
          "url": "https://help.shopify.com/en/manual/apps/uninstalling-apps",
          "checked": "2026-10-10",
          "claims": [
            "App uninstall can leave theme code.",
            "Separately billed subscriptions may need cancellation outside Shopify."
          ]
        }
      ],
      "related": [
        "guide-shopify-theme-update-regression",
        "guide-shopify-app-uninstall-cleanup",
        "shopify-product-tab-after-theme-update",
        "shopify-uninstalled-review-app-residue",
        "shopify-merchant-brand-identifier"
      ],
      "sections": [
        {
          "heading": "Theme settings and custom code have different lifecycles",
          "body": [
            "A theme update can carry editor customisations forward while incompatible hand-edited or app-generated code does not transfer. A product tab disappearing therefore needs a comparison of the old theme, updated draft and the custom feature; simply republishing the new version is not a diagnosis."
          ],
          "items": [
            "Identify the exact product template and lost behaviour.",
            "Review the update's code-transfer status and release notes.",
            "Keep the old theme available as a reference before publishing a draft."
          ]
        },
        {
          "heading": "An uninstall is not complete storefront cleanup",
          "body": [
            "Shopify warns that app code can remain in the theme after uninstall. Removing a review app also raises a data question: what review content or export needs preserving? The app developer's cleanup instructions and billing controls matter; Shopify uninstall does not necessarily cancel a separately billed service."
          ],
          "items": [
            "Name the removed app and affected snippets or widgets without sharing account access.",
            "Preserve any authorised export before deleting display code.",
            "Check unrelated storefront features that share the modified template."
          ]
        },
        {
          "heading": "Keep catalogue and feed problems separate",
          "body": [
            "A storefront layout regression is not the same as a product-feed rejection for identifiers. Brand and identifier correction needs the actual channel's rejection reason and product facts. Do not invent a GTIN or brand merely to clear a warning; the separate catalogue outcome covers a different deliverable and acceptance test."
          ],
          "items": [
            "Preview themes before live publication.",
            "Do not place test orders, change billing or install apps without the account holder's authority."
          ]
        },
        {
          "heading": "Request a bounded change",
          "body": [
            "Describe the named product page, old and new behaviour, theme versions and preceding app or theme change. Public links and redacted screenshots are useful first-contact inputs. No staff invitation, private export or credentials are needed for the initial enquiry; the proposed work is scoped and quoted before access."
          ],
          "items": []
        }
      ],
      "incoming": [
        "buyer-ecommerce-owner-checkout",
        "guide-merchant-brand-identifiers",
        "guide-shopify-theme-update-regression",
        "guide-shopify-app-uninstall-cleanup",
        "example-shopify-product-csv-damage-before-after",
        "example-store-stock-reconciliation-sheet",
        "guide-shopify-csv-import-handle-overwrite-blank-cells",
        "guide-shopify-discount-combination-rules",
        "guide-shopify-abandoned-checkout-when-no-email",
        "guide-shopify-inventory-locations-set-versus-adjust",
        "guide-store-catalogue-move-option-variant-limits",
        "guide-store-redirects-and-launch-checks-after-replatform",
        "buyer-store-owner-moving-platforms"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/platforms/shopify/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/platforms/shopify/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fplatforms%2Fshopify%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fplatforms%2Fshopify%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "example-shopify-product-csv-damage-before-after",
      "type": "example",
      "title": "Synthetic worked example: a Shopify import that blanked a vendor and removed variants",
      "description": "Inspect invented rows showing how an import with a blank column and missing option columns changes a product, and the corrective file that restores it.",
      "slug": "shopify-product-csv-damage-before-after",
      "url": "/examples/shopify-product-csv-damage-before-after/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Shopify Help Center: Importing products with a CSV file",
          "url": "https://help.shopify.com/en/manual/products/import-export/import-products",
          "checked": "2026-10-11",
          "claims": [
            "A blank cell in a non-required column erases the stored value, and a column left out of the file leaves stored values unchanged.",
            "Including SKU without the option name and value columns removes variants.",
            "Changing an option value deletes existing variant IDs and creates new ones."
          ]
        },
        {
          "label": "Shopify Help Center: Product CSV file format",
          "url": "https://help.shopify.com/en/manual/products/import-export/using-csv",
          "checked": "2026-10-11",
          "claims": [
            "Variant rows repeat the handle and leave title, description, vendor and tags empty.",
            "A single-option product uses Default Title.",
            "If variant-dependent columns such as SKU are included, the option name and value columns must be included too."
          ]
        }
      ],
      "related": [
        "shopify-csv-import-merged-or-overwrote-products",
        "guide-shopify-csv-import-handle-overwrite-blank-cells",
        "platform-shopify",
        "store-catalogue-mapping-to-shopify-csv"
      ],
      "sections": [
        {
          "heading": "What this example is",
          "body": [
            "This is an invented fixture, not a customer record and not an executed repair. The store, product, SKUs and prices are made up. Header names follow the names on Shopify's product CSV page when checked; always confirm headers against a template exported from your own store, because headers are case sensitive. The option name shown for a default variant is illustrative."
          ],
          "items": [
            "One product, three size variants, one vendor.",
            "One import file with a blank vendor column and no option columns."
          ]
        },
        {
          "heading": "The reference: the export taken before the import",
          "body": [
            "The reference holds the product as it should be. One product has three variants, and the vendor is filled in on the first row only."
          ],
          "items": [],
          "code": "URL handle,Title,Vendor,Option1 name,Option1 value,SKU,Price\ntrail-sock,Trail Sock,Northfield Outfitters,Size,S,TS-S,9.00\ntrail-sock,,,Size,M,TS-M,9.00\ntrail-sock,,,Size,L,TS-L,9.00"
        },
        {
          "heading": "The file that was imported, with overwrite on",
          "body": [
            "The imported file came from a supplier spreadsheet. It has a Vendor column that is empty in this row, a SKU and a price, and no option columns."
          ],
          "items": [],
          "code": "URL handle,Title,Vendor,SKU,Price\ntrail-sock,Trail Sock,,TS-S,10.00"
        },
        {
          "heading": "What the store holds afterwards",
          "body": [
            "Three things happened, each documented by Shopify. The blank vendor cell erased the stored vendor. The price changed because the column was present and overwrite was on. Because SKU was included without the option name and value columns, the existing variants were replaced by one default variant. The other two sizes, M and L, are gone from the product, and their old variant IDs cannot be recovered from a file."
          ],
          "items": [],
          "code": "URL handle,Title,Vendor,Option1 name,Option1 value,SKU,Price\ntrail-sock,Trail Sock,,Title,Default Title,TS-S,10.00"
        },
        {
          "heading": "The corrective file",
          "body": [
            "The corrective file is built from the reference, limited to the affected handle and the columns that need restoring, and it keeps the option columns together with the SKU. It restores the vendor, the three sizes and the original prices. The variants it creates are new records with new IDs, so any app that relied on the old IDs has to be re-linked."
          ],
          "items": [],
          "code": "URL handle,Title,Vendor,Option1 name,Option1 value,SKU,Price\ntrail-sock,Trail Sock,Northfield Outfitters,Size,S,TS-S,9.00\ntrail-sock,,,Size,M,TS-M,9.00\ntrail-sock,,,Size,L,TS-L,9.00"
        },
        {
          "heading": "How the result would be checked",
          "body": [
            "The check starts from the damage, not from the reference. A separate test store is seeded with the damaged product, using the file shown under \"What the store holds afterwards\", and exported. That export must show the problem: the vendor blank, the price 10.00 and one default variant where the reference has three. If the seeded store does not show the damage, the test has not reproduced the problem and proves nothing. The corrective file is then imported, the products are re-exported and compared with the reference column by column. The check passes only if the comparison shows no difference in the agreed columns, the variant count is three, and no other product in the test store changed. Importing on the live store, after exporting its products again, is a separate step taken by the store owner."
          ],
          "items": [
            "Before, on the seeded test store: variant count 1, vendor blank, price 10.00.",
            "After, on the same store: variant count 3, vendor restored, price 9.00 on each variant.",
            "Other products in the test store: unchanged."
          ]
        },
        {
          "heading": "What this example does not show",
          "body": [
            "It does not show stock counts, images or apps. The CSV inventory quantity applies to single-location stores only, image rows can be lost when a file is sorted in a spreadsheet, and old variant IDs cannot be restored. A real repair lists those limits for the specific store before any file is built."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-shopify-csv-import-handle-overwrite-blank-cells",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/shopify-product-csv-damage-before-after/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/examples/shopify-product-csv-damage-before-after/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Fshopify-product-csv-damage-before-after%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fexamples%2Fshopify-product-csv-damage-before-after%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "example-store-stock-reconciliation-sheet",
      "type": "example",
      "title": "Synthetic worked example: reconciling Shopify stock with a warehouse list",
      "description": "Inspect an invented four-product reconciliation showing how a written rule turns raw stock numbers into matches, explained gaps and one real finding.",
      "slug": "store-stock-reconciliation-sheet",
      "url": "/examples/store-stock-reconciliation-sheet/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Shopify developer documentation: Inventory management apps",
          "url": "https://shopify.dev/docs/apps/build/orders-fulfillment/inventory-management-apps",
          "checked": "2026-10-11",
          "claims": [
            "On hand is the sum of available, committed, reserved, damaged, safety stock and quality control, and available is what can be sold.",
            "An adjust mutation applies a change while a set mutation writes an absolute value."
          ]
        },
        {
          "label": "Shopify Admin GraphQL: inventorySetQuantities",
          "url": "https://shopify.dev/docs/api/admin-graphql/latest/mutations/inventorySetQuantities",
          "checked": "2026-10-11",
          "claims": [
            "A set mutation compares the stored quantity with a supplied value unless the comparison is ignored, which protects against concurrent writers."
          ]
        }
      ],
      "related": [
        "inventory-shopify-stock-out-of-step-with-connected-system",
        "store-keep-order-inventory-sync-healthy",
        "guide-shopify-inventory-locations-set-versus-adjust",
        "guide-store-reconciling-orders-and-stock-between-systems",
        "platform-shopify"
      ],
      "sections": [
        {
          "heading": "What this example is",
          "body": [
            "This is an invented fixture for one location, not a customer record and not a result from a real store. The products, quantities and rule are made up to show the method. Nothing here was executed against a live system."
          ],
          "items": [
            "One Shopify location, four products.",
            "The other system reports units on the shelf and units allocated to open orders.",
            "Rule R1, written down before comparing: sellable stock equals on shelf minus allocated, and Shopify available should equal it."
          ]
        },
        {
          "heading": "The reconciliation sheet",
          "body": [
            "Each row compares the same product at the same location at the same time. Shopify committed units are shown so that the committed state is not mistaken for drift."
          ],
          "items": [],
          "code": "SKU     Location   Shopify  Shopify    Other system  Other system  Rule R1: sellable =     Diff   Status\n                   avail.   committed  on shelf      allocated     on shelf - allocated\nTS-S    Main       12       3          15            3             12                       0     match\nTS-M    Main       8        2          12            2             10                       -2    explained: 2 units received, not yet in Shopify\nTS-L    Main       5        0          5             0             5                        0     match\nTS-XL   Main       20       0          16            2             14                       +6    UNEXPLAINED: check sync log for an absolute write"
        },
        {
          "heading": "Reading each row",
          "body": [
            "TS-S and TS-L match under the rule. TS-M differs by two, and the reason is a recorded event: two units were received in the warehouse list and have not reached Shopify yet, so it is explained and should clear on the next run. TS-XL differs by six with no recorded reason, so it is the finding. Shopify shows more sellable stock than the warehouse list says exists."
          ],
          "items": [
            "A zero difference needs no action.",
            "An explained difference gets an owner and a date to clear.",
            "An unexplained difference is investigated before anything is changed."
          ]
        },
        {
          "heading": "What would be checked next for the unexplained row",
          "body": [
            "A typical cause for Shopify showing more than the other system is an absolute write that was based on an older read, so sales made in between were erased. The check is to compare the sync log with Shopify's adjustment history for that product around the time of the last run: was a total written, and were there sales just afterwards? A sync that compares before writing, or sends changes instead of totals, would not erase them. This is a hypothesis to test, not a conclusion."
          ],
          "items": [
            "Compare the time of the last sync write with the times of recent orders for the product.",
            "Check whether the sync writes a total or a change.",
            "Check which Shopify location the sync wrote to."
          ]
        },
        {
          "heading": "What a clean result looks like",
          "body": [
            "After a correction, the same sheet is rebuilt on a test store: every difference is zero or explained, a repeat run changes nothing, and a test sale reduces both systems once. The sheet is evidence for the person accepting the work, who can recompute any row from the two exports."
          ],
          "items": []
        },
        {
          "heading": "What this example leaves out",
          "body": [
            "It leaves out more than one location, damaged or reserved stock, product-code mismatches and any count of physical stock. A physical count is the owner's decision, and a reconciliation cannot say what is truly on the shelf."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-shopify-inventory-locations-set-versus-adjust",
        "guide-store-reconciling-orders-and-stock-between-systems",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/store-stock-reconciliation-sheet/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/examples/store-stock-reconciliation-sheet/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Fstore-stock-reconciliation-sheet%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fexamples%2Fstore-stock-reconciliation-sheet%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "example-woocommerce-test-order-matrix",
      "type": "example",
      "title": "Synthetic worked example: an eight-case WooCommerce test-order matrix",
      "description": "Inspect an invented test-order script with the expected result for each journey, written before running it on a staging copy.",
      "slug": "woocommerce-test-order-matrix",
      "url": "/examples/woocommerce-test-order-matrix/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "WooCommerce documentation: Order statuses",
          "url": "https://woocommerce.com/document/managing-orders/order-statuses/",
          "checked": "2026-10-11",
          "claims": [
            "Processing means paid with stock deducted, Pending payment means no payment has arrived, and Failed or Cancelled orders return stock to inventory."
          ]
        },
        {
          "label": "WooCommerce documentation: How to test for conflicts",
          "url": "https://woocommerce.com/document/how-to-test-for-conflicts/",
          "checked": "2026-10-11",
          "claims": [
            "A staging clone or a backup protects the live store while testing, and browser caching should be disabled while testing."
          ]
        },
        {
          "label": "Stripe documentation: Receive Stripe events in your webhook endpoint",
          "url": "https://docs.stripe.com/webhooks",
          "checked": "2026-10-11",
          "claims": [
            "The Event deliveries tab lists events as Delivered, Pending or Failed with the HTTP status code, and events can be resent from the Dashboard.",
            "Duplicate deliveries should be identified by event ID."
          ]
        }
      ],
      "related": [
        "checkout-keep-test-order-passing-through-updates",
        "store-recovery-woocommerce-after-failed-update",
        "guide-woocommerce-update-test-order-script",
        "guide-woocommerce-pending-payment-gateway-confirmation",
        "platform-wordpress-woocommerce"
      ],
      "sections": [
        {
          "heading": "What this example is",
          "body": [
            "This is an authored specification, not an executed test and not a client result. The product, coupon code and zones are invented. It shows the shape of a script: each case names the journey, the setup and the expected result, written before anything is run. A real script is built around your products, your destinations and your payment method."
          ],
          "items": [
            "Runs on a staging copy with payments in test mode and customer email redirected.",
            "The same eight cases are run before and after the updates under test."
          ]
        },
        {
          "heading": "The matrix",
          "body": [
            "Run the cases in order. For each, record the order number, status, total, stock figure and a screenshot, and note anything that differs from the expected column."
          ],
          "items": [],
          "code": "ID  Journey                         Setup                          Expected result\nT1  Guest, simple product           Test card, address zone A      Order Processing; stock -1 once; total = price + zone A rate\nT2  Signed-in, variable product     Size M, colour Navy            Cart holds the Size M / Navy variation; correct price\nT3  Shipping, zone B                Postcode inside zone B         Zone B methods and costs as in the destination table\nT4  Shipping, not served            Address in an excluded region  No shipping method shown\nT5  Coupon                          Code SPRING10 on one product   One discount line; total as expected\nT6  Declined payment                Test decline card              No paid order; stock unchanged or returned\nT7  Confirmation email              Test inbox                     One order email with correct lines and total\nT8  Gateway confirmation, resent    Provider log; resend T1 event  Event delivered, order moves on; after the resend no second status change, stock unchanged"
        },
        {
          "heading": "Why these cases",
          "body": [
            "T1 and T2 carry the main buying path and the variation match. T3 and T4 test that shipping zones give the right result and the right refusal. T5 covers the one coupon the store actually uses. T6 checks that a failure leaves no paid order behind, which matters because failed orders return stock. T7 checks the email a customer actually receives. T8 tests the part that fails silently: whether the provider's confirmation reaches the store, and whether a resent delivery is harmless, since duplicates can occur and are identified by event ID."
          ],
          "items": []
        },
        {
          "heading": "How a result is read",
          "body": [
            "A case passes only if every part of its expected result holds. A case that fails after an update and passed before it points at the update, and the next step is to isolate which component changed, on the copy, by switching to a default theme and deactivating other plugins one at a time. A pass on all eight says those cases worked on the copy with those updates. It does not say live checkout works, so one real order is placed on live after updating."
          ],
          "items": [
            "Pass: every part of the expected result holds.",
            "Fail: record what happened instead, with evidence.",
            "Not run: say why; it is not a pass."
          ]
        },
        {
          "heading": "What the matrix leaves out",
          "body": [
            "It leaves out performance, security checks, accessibility, subscriptions and any custom plugin behaviour. Add a case for each journey that carries money in your store, and remove cases that no one would notice failing. The standing service this shape comes from runs a script of up to eight cases, so this matrix is the largest shape it covers."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-woocommerce-update-test-order-script",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/woocommerce-test-order-matrix/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/examples/woocommerce-test-order-matrix/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Fwoocommerce-test-order-matrix%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fexamples%2Fwoocommerce-test-order-matrix%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-shopify-csv-import-handle-overwrite-blank-cells",
      "type": "guide",
      "title": "How a Shopify CSV import overwrites products, and how to see what it changed",
      "description": "Why an import can blank fields or strip variants from products you did not mean to touch, and how to compare files to find exactly what changed.",
      "slug": "shopify-csv-import-handle-overwrite-blank-cells",
      "url": "/guides/shopify-csv-import-handle-overwrite-blank-cells/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Shopify Help Center: Importing products with a CSV file",
          "url": "https://help.shopify.com/en/manual/products/import-export/import-products",
          "checked": "2026-10-11",
          "claims": [
            "Rows are matched to existing products by handle, and header names are case sensitive.",
            "With the overwrite option selected, values in the columns present in the file replace the stored values; without it, products with matching handles are skipped.",
            "A blank cell in a non-required column erases the stored value, while a column left out of the file leaves the stored values unchanged.",
            "Including variant columns without the option name and value columns can remove the variant option.",
            "Changing an option value deletes the existing variant IDs and creates new ones, and there is no import history.",
            "The maximum file size is 15 MB."
          ]
        },
        {
          "label": "Shopify Help Center: Product CSV file format",
          "url": "https://help.shopify.com/en/manual/products/import-export/using-csv",
          "checked": "2026-10-11",
          "claims": [
            "Variant rows repeat the handle and leave title, description, vendor and tags empty.",
            "If variant-dependent columns such as SKU are included, the option name and option value columns must be included too, or a new default variant is created and existing variants are deleted.",
            "Inventory quantity in the CSV applies to single-location stores only."
          ]
        }
      ],
      "related": [
        "shopify-csv-import-merged-or-overwrote-products",
        "platform-shopify",
        "guide-store-catalogue-move-option-variant-limits",
        "example-shopify-product-csv-damage-before-after",
        "guide-shopify-inventory-locations-set-versus-adjust"
      ],
      "sections": [
        {
          "heading": "Shopify decides what to change from the handle and the columns in the file",
          "body": [
            "A Shopify product import does not look at product titles. It matches each row to an existing product by the URL handle, and it reads only the columns that are present in the file. Those two facts explain most surprising results. If a row carries a handle that already exists and the overwrite option is ticked, every value in that row's columns replaces what the product holds. If the overwrite option is not ticked, the same row is skipped and the product keeps what it had.",
            "Column headers must also match exactly. Shopify documents that headers are case sensitive, so a lowercase handle column is not the same as the header it expects, and a missing or mismatched header makes the import fail rather than guess."
          ],
          "items": [
            "A product is identified by its handle, not its title.",
            "Overwrite on means matching products take the file's values for the columns it contains.",
            "A column absent from the file is left alone, so deleting a column is a way to protect a field."
          ]
        },
        {
          "heading": "Three ways an import quietly damages products you did not mean to change",
          "body": [
            "The first is the blank cell. Shopify documents that a blank cell in a non-required column erases the stored value, so a vendor column exported empty from another system clears every vendor on every matching product. The fix is to remove the column from the file, not to leave it blank.",
            "The second is a variant column without its option columns. If the file includes something that belongs to a variant, such as the SKU or weight, but not the option name and value columns, Shopify can create a new default variant and delete the existing ones. A product that had sizes and colours ends up with one variant. The third is an option value change. Changing the value of an option deletes the existing variant IDs and creates new ones, and the page warns this can break third-party tools that rely on those IDs. A spreadsheet cannot put the old IDs back."
          ],
          "items": [
            "Sorting a file in a spreadsheet can break the link between a product row and its image rows, so images are lost or misattached.",
            "Curly quotes and files that are not UTF-8 cause quoting errors and garbled characters.",
            "Moving an existing option to a different position in the same import can fail with a \"Line is invalid\" message; the documented workaround is to import under a temporary option name first, then again with the final name."
          ]
        },
        {
          "heading": "What you cannot rely on afterwards",
          "body": [
            "Shopify tells you plainly that an import cannot be cancelled once it starts and that there is no import history. A confirmation email arrives after upload, and the store activity log shows changes, but neither gives you the old values. The only way back to the old values is a file that holds them, which is why the advice on the import page is to export your products first and to test large imports on a development store.",
            "That also sets the practical limit on any repair. If there is no export from before the import, and no supplier or source file with the right values, nobody can know what to put back. The repair is then a data-entry decision for you, not something a file can solve."
          ],
          "items": []
        },
        {
          "heading": "A safe first investigation, with no logins shared",
          "body": [
            "Do not import again yet. A second import with overwrite on can damage the products a second time. Instead, take a fresh export of the affected products today so the current state is preserved, find the export taken before the damaging import, and find the file that was imported. Open the three files side by side."
          ],
          "items": [
            "Compare the header rows. Look for headers that exist in one file and not another, and for a column that was empty in the imported file.",
            "Pick three affected handles and compare every column across the three files.",
            "Count the variant rows per handle in the pre-import export and in the current export.",
            "Look at the store activity log for the time of the import to confirm which products it touched.",
            "Check whether an app depends on variant IDs, such as subscriptions, bundles or inventory sync."
          ]
        },
        {
          "heading": "What fixes it, and what does not fit",
          "body": [
            "A repair is a corrective file that holds only the affected handles and only the columns that need restoring, built from the pre-import reference. It should be imported on a separate test store first, one that has been loaded with the damaged products so the test starts from the same damage, then re-exported and compared with the reference. Only when that comparison shows no differences should the same file be imported on the live store, after another fresh export as a safety copy.",
            "Some things a file cannot fix. It cannot restore variant IDs that Shopify discarded. It cannot restore stock counts for a store with more than one location, because the inventory quantity column in the CSV applies to single-location stores only. It cannot fix problems that were never in the product data, such as a theme that displays a field badly."
          ],
          "items": []
        },
        {
          "heading": "How the paid repair is accepted",
          "body": [
            "The fixed job for this problem, put products back after a damaging import, is accepted on evidence you can check yourself: a fresh export from the test store, which first showed the damage, matches your reference in every agreed column for every agreed product, variant counts and option values match, and the corrective file touches only the agreed handles and columns. We work from your files and a test store; we do not log in to the live store, and you run the live import."
          ],
          "items": []
        }
      ],
      "incoming": [
        "example-shopify-product-csv-damage-before-after",
        "guide-store-catalogue-move-option-variant-limits",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/shopify-csv-import-handle-overwrite-blank-cells/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/shopify-csv-import-handle-overwrite-blank-cells/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fshopify-csv-import-handle-overwrite-blank-cells%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fshopify-csv-import-handle-overwrite-blank-cells%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-shopify-discount-combination-rules",
      "type": "guide",
      "title": "Why a Shopify discount is refused or stacks wrongly: classes, limits and calculation order",
      "description": "How Shopify decides whether two discounts can combine, which limits apply per order and which settings explain the messages customers see.",
      "slug": "shopify-discount-combination-rules",
      "url": "/guides/shopify-discount-combination-rules/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Shopify Help Center: Combining discounts",
          "url": "https://help.shopify.com/en/manual/discounts/discount-combinations",
          "checked": "2026-10-11",
          "claims": [
            "Discounts belong to the product, order or shipping class and never combine by default; both discounts in a pair must allow the combination.",
            "Up to 25 active automatic discounts, and up to 5 product or order codes plus 1 shipping code, can apply to one order.",
            "Product discounts apply first, then order discounts on the reduced subtotal, then shipping discounts.",
            "Stacked percentage order discounts are each figured on the same subtotal rather than compounding.",
            "Customers who enter codes that cannot stack see a message that the discount could not be used with existing discounts.",
            "Combinations work only in the Online Store, the Storefront API and Shopify POS, not on external checkouts.",
            "Discounts worth zero may misbehave, and a discount's type and method cannot be edited after creation.",
            "Third-party app discounts combine only if the app developer supports the combinations API."
          ]
        },
        {
          "label": "Shopify Help Center: Discount codes",
          "url": "https://help.shopify.com/en/manual/discounts/discount-types/discount-codes",
          "checked": "2026-10-11",
          "claims": [
            "A minimum purchase requirement, usage limits, active dates, and product or collection limits can restrict a code.",
            "A one-use-per-customer limit applies only to that specific discount, so a deleted and re-created copy can be used once by past users.",
            "A single code can be tied to at most 100 customers, products and variants combined.",
            "Start and end times follow the time zone in the Shopify admin.",
            "Special characters in a code name may stop it being added to the checkout URL.",
            "Codes cannot be used on the post-purchase page, and a code applied at checkout does not carry over to post-purchase offers."
          ]
        }
      ],
      "related": [
        "shopify-discount-code-not-applying-as-intended",
        "platform-shopify",
        "collection-store-checkout-order-flow-diagnosis",
        "guide-shopify-abandoned-checkout-when-no-email"
      ],
      "sections": [
        {
          "heading": "A discount has a class, and classes never mix unless both sides agree",
          "body": [
            "Every Shopify discount belongs to one of three classes: product discounts, which target particular items or collections; order discounts, which reduce the cart subtotal; and shipping discounts, which lower delivery cost. Shopify's rule is that discounts never combine by default. Each one must be set to allow the classes it can pair with, and both discounts in a pair have to permit the combination. A promotion that works on its own can therefore be refused the moment a second one is in the basket, simply because one of the two settings was left at its default.",
            "Not every pairing is available to every store. Order with shipping, product with shipping, and product with product on different items are documented as available to all merchants. Product with order, and order with order, are limited to eligible merchants. Two shipping discounts on the same order are not supported."
          ],
          "items": [
            "Open both discounts and read the combination section of each, not just the one you are testing.",
            "Check the plan-dependent pairings against what your store is allowed."
          ]
        },
        {
          "heading": "The limits, the calculation order and what the customer sees",
          "body": [
            "One order can carry up to 25 active automatic discounts and up to five product or order codes plus one shipping code. Calculation runs in a fixed order: product discounts on individual items, then order discounts on the reduced subtotal, then shipping. Stacked percentage order discounts are each worked out on the same subtotal rather than compounding, so ten percent and twenty percent on 100 is 70, not 72. When a percentage and a fixed order discount combine, the percentage is applied first.",
            "When discounts cannot combine, Shopify gives the customer whichever discount or combination is best for their basket. A customer who types codes that cannot stack sees a message saying the code could not be used with existing discounts. A shipping discount that cannot combine with a product or order discount loses to them, and the customer may be told they already have a better combination."
          ],
          "items": [
            "Two product discounts of equal value on the same item: either may win.",
            "Buy X get Y discounts have their own stacking rule on non-Plus plans: items in the promotion cannot receive further product discounts."
          ]
        },
        {
          "heading": "Settings that look unrelated but refuse a code",
          "body": [
            "Combination is only one cause. A minimum purchase requirement means a code does nothing below the amount. A usage limit may count per customer, and Shopify notes a one-use-per-customer limit belongs to that discount only, so deleting a discount and recreating it with the same limit lets customers who used the old discount use the copy once. Start and end times follow the time zone set in the admin, so a code that starts at midnight starts at midnight in that zone, not the customer's. A code can be limited to products or collections, and one code can be tied to at most 100 customers, products and variants combined; going over that gives an admin-side error, not a customer message.",
            "Two further cases cause confusion. A discount worth zero dollars or zero percent can misbehave, so use at least the smallest valid amount. And a discount's type and method cannot be edited after creation; if the type was wrong, the discount has to be deleted and recreated, which also resets its per-customer usage."
          ],
          "items": [
            "Special characters in a code name may stop it being added to a checkout link; type the code by hand first.",
            "Combinations do not work on external checkouts such as social channels.",
            "Discounts created by a third-party app combine only if its developer supports the combinations API."
          ]
        },
        {
          "heading": "A safe first investigation using a basket matrix",
          "body": [
            "Write down five baskets as rows: the items, whether the shopper is signed in, the shipping country and the codes entered, and what you expect to pay for each. Run them on a test store with the same discount settings, not on live checkout, and compare. A matrix turns a vague complaint, the code does not work, into a specific one: this basket, with these two discounts, gives this total instead of that one."
          ],
          "items": [
            "Include one basket that should be refused, so the refusal itself is tested.",
            "Include a second use by the same test customer if the code has a per-customer limit.",
            "Record the message shown, not just the total."
          ]
        },
        {
          "heading": "What does not fit",
          "body": [
            "Custom logic written into the checkout, discounts created by an app that does not support combinations, gift cards and store credit, and post-purchase offers are outside what settings can fix. Shopify notes that codes cannot be used on the post-purchase page, and a code applied at checkout does not carry into post-purchase offers."
          ],
          "items": []
        },
        {
          "heading": "How the paid check is accepted",
          "body": [
            "The fixed job for this problem makes your discount settings produce the totals you specify. It is accepted when every basket on the agreed list gives the expected discount lines and total on a test store, a basket that should be refused is refused with the message you expect, a per-customer limit behaves as agreed, and the written settings reproduce the same totals on a fresh test store. You decide the promotion; we do not advise on offers or consent wording."
          ],
          "items": []
        }
      ],
      "incoming": [
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/shopify-discount-combination-rules/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/shopify-discount-combination-rules/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fshopify-discount-combination-rules%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fshopify-discount-combination-rules%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-shopify-abandoned-checkout-when-no-email",
      "type": "guide",
      "title": "Shopify abandoned checkout emails: when none is sent, and how to test yours",
      "description": "What counts as an abandoned checkout, the cases where Shopify sends no recovery email, and a three-scenario test you can run with your own address.",
      "slug": "shopify-abandoned-checkout-when-no-email",
      "url": "/guides/shopify-abandoned-checkout-when-no-email/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Shopify Help Center: Abandoned checkouts",
          "url": "https://help.shopify.com/en/manual/orders/abandoned-checkouts",
          "checked": "2026-10-11",
          "claims": [
            "A checkout is abandoned when the customer has entered an email address but has not paid and it stays unfinished for over ten minutes.",
            "Recovery applies only to the Online Store and Buy Button channels; point-of-sale and third-party channel checkouts get no recovery email.",
            "The automation is edited in Messaging automations, with settings to send automatically, who to send to and how long after abandonment.",
            "No email is sent if the customer completed a purchase before it was due, a payment processing error occurred, the shop does not ship to the address, the customer gave a phone number instead of an email, no product is available, everything is free, or Shopify Payments blocked the payment as high risk.",
            "For business-to-business stores the feature is off by default and Shopify Support must activate it.",
            "Anyone who opens a recovery link can continue the checkout, and a sent link cannot be disabled or expired."
          ]
        },
        {
          "label": "Shopify Help Center: Test orders",
          "url": "https://help.shopify.com/en/manual/checkout-settings/test-orders",
          "checked": "2026-10-11",
          "claims": [
            "Customers cannot place live orders while payment providers are in test mode.",
            "Processing an order with a real payment provider and then cancelling and refunding it is another test option, and the payment processor's fees may apply."
          ]
        }
      ],
      "related": [
        "shopify-abandoned-checkout-emails-not-sending",
        "platform-shopify",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "sections": [
        {
          "heading": "What Shopify counts as an abandoned checkout",
          "body": [
            "Shopify records a checkout as abandoned when the shopper has entered an email address, has not paid, and the checkout then stays unfinished for more than ten minutes. Shopify notes that cart contents are not saved. Recovery works only for checkouts made on the Online Store and Buy Button channels, so someone who started a purchase at a point-of-sale terminal or on a third-party channel never receives a recovery email, whatever your settings say.",
            "The email itself carries a link back to the unfinished checkout. You can edit the template to add a logo or change colours, and you can send the link by hand from the abandoned checkout record."
          ],
          "items": []
        },
        {
          "heading": "Where the setting lives and what it controls",
          "body": [
            "The automation is called abandoned checkout emails by Shopify and sits under Messaging automations. Its settings let you turn sending on, choose which category of visitor receives the email, and choose how long after abandonment it is sent. The documentation does not list the recipient categories or delay options in the page, so read them on your own screen and record what you see before changing anything. For a business-to-business store the feature is off by default, and the store owner has to ask Shopify Support to activate it."
          ],
          "items": [
            "Confirm the automation is switched on.",
            "Write down the recipient category and the delay.",
            "Note whether the store is a business-to-business store."
          ]
        },
        {
          "heading": "The cases where no email is sent",
          "body": [
            "Shopify lists the situations where it does not send a recovery email. Several of them look like a fault from the owner's side, so check an actual abandoned checkout against this list before suspecting the setting."
          ],
          "items": [
            "The customer completed a purchase before the email was due.",
            "A payment processing error occurred.",
            "Your shop does not ship to the customer's address.",
            "The customer gave a phone number instead of an email address.",
            "None of the products in the checkout is available to buy.",
            "Everything in the checkout is free and the customer did not reach the shipping page, or shipping is also free.",
            "Shopify Payments blocked the payment as high risk."
          ]
        },
        {
          "heading": "A three-scenario test you can run yourself",
          "body": [
            "You can test the path with your own email address and a low-value product, always stopping before payment. Run three scenarios and write down the time you started each one. Scenario one is an eligible checkout with your email address that you leave open past the delay. Scenario two is a checkout with only a phone number. Scenario three is a checkout to an address you do not ship to. Only the first should produce a reminder; the other two should produce none.",
            "The case where a shopper finishes the purchase before the email is due is a documented exception, but proving it on your store needs a completed order. Shopify says customers cannot place live orders while its payment test mode is on, and an order paid for and then refunded may still carry fees from your payment processor. So the test above leaves that case to Shopify's published rule instead of asking you to run it.",
            "If the first scenario fails, check whether the email arrived in spam. A reminder in the spam folder means the store setting works and the fault is mail delivery, which is a separate email authentication job, not a setting change."
          ],
          "items": [
            "Use only your own address; never test with a real customer's details.",
            "Record when each email arrived and whether the link opens that checkout.",
            "Remember that anyone with the link can continue the checkout, so do not forward test links."
          ]
        },
        {
          "heading": "What fixes it, and what does not fit",
          "body": [
            "Fixes are almost always settings: switching the automation on, choosing the recipients and delay you intend, activating the feature on a business-to-business store through Shopify Support, or repairing a template that dropped the recovery link. Shopify does not recover checkouts from other channels, and marketing consent and email privacy rules are for you or your adviser; they are not something a settings fix decides."
          ],
          "items": []
        },
        {
          "heading": "How the paid check is accepted",
          "body": [
            "The fixed job for this problem is accepted on three test results that you run, each stopping before payment, and we interpret: an eligible checkout produces one reminder after the configured delay and its link opens that checkout, a phone-number-only checkout produces none, and a checkout to an address you do not ship to produces none, matching the documented exceptions. The settings we write down must match what your admin shows after you apply them. We never log in to your store."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-shopify-discount-combination-rules",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/shopify-abandoned-checkout-when-no-email/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/shopify-abandoned-checkout-when-no-email/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fshopify-abandoned-checkout-when-no-email%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fshopify-abandoned-checkout-when-no-email%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-shopify-inventory-locations-set-versus-adjust",
      "type": "guide",
      "title": "Why Shopify stock drifts from another system: locations, quantity states and set versus adjust",
      "description": "How Shopify stores stock per location and in several states, why writing absolute numbers can erase sales, and how to reconcile a sample safely.",
      "slug": "shopify-inventory-locations-set-versus-adjust",
      "url": "/guides/shopify-inventory-locations-set-versus-adjust/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Shopify developer documentation: Inventory management apps",
          "url": "https://shopify.dev/docs/apps/build/orders-fulfillment/inventory-management-apps",
          "checked": "2026-10-11",
          "claims": [
            "Inventory states describe stock at a specific location, and adjustments target a product, a state and a location.",
            "inventoryAdjustQuantities applies a relative change, while inventorySetQuantities writes an absolute value for on hand or available.",
            "On hand is the sum of available, committed, reserved, damaged, safety stock and quality control, and committed quantities cannot be changed through the Admin API.",
            "Changes to committed, reserved, damaged, safety stock and quality control do not fire webhooks, so apps that depend on them need to query.",
            "A reference document URI can record which system triggered a change."
          ]
        },
        {
          "label": "Shopify Admin GraphQL: inventorySetQuantities",
          "url": "https://shopify.dev/docs/api/admin-graphql/latest/mutations/inventorySetQuantities",
          "checked": "2026-10-11",
          "claims": [
            "inventorySetQuantities should be used only by a system that is the authoritative source for stock counts; otherwise inventoryAdjustQuantities is advised.",
            "Unless the comparison is ignored, the update goes through only if the stored quantity equals the supplied compare quantity, which protects against concurrent writers.",
            "In the current documentation version an idempotency key is required through the idempotent directive."
          ]
        },
        {
          "label": "Shopify Help Center: Locations",
          "url": "https://help.shopify.com/en/manual/locations/managing-locations",
          "checked": "2026-10-11",
          "claims": [
            "Locations let a merchant track inventory separately at each physical location.",
            "Some apps, such as dropshipping tools and outside fulfilment services, can themselves count as locations."
          ]
        },
        {
          "label": "Shopify Help Center: Product CSV file format",
          "url": "https://help.shopify.com/en/manual/products/import-export/using-csv",
          "checked": "2026-10-11",
          "claims": [
            "Inventory quantity in the product CSV applies to single-location stores only."
          ]
        }
      ],
      "related": [
        "inventory-shopify-stock-out-of-step-with-connected-system",
        "platform-shopify",
        "store-keep-order-inventory-sync-healthy",
        "example-store-stock-reconciliation-sheet",
        "guide-store-reconciling-orders-and-stock-between-systems"
      ],
      "sections": [
        {
          "heading": "Stock in Shopify is per variant, per location, and in several states",
          "body": [
            "A number in the Shopify admin hides structure. Stock is held for a product variant at each location, and at each location it is split into states. Shopify's developer documentation defines on hand as the sum of available, committed, reserved, damaged, safety stock and quality control. Available is what can be sold. Committed covers unfulfilled orders, reserved draft-order items and transfers or shipments marked ready to ship. Reserved, damaged, safety stock and quality control appear as unavailable in the admin.",
            "This matters for any sync, because another system's single stock figure usually corresponds to only one of these states. If your warehouse system reports units on the shelf and Shopify reports available, the difference is exactly the committed and reserved units. Comparing the two without naming the state produces a gap that looks like drift but is arithmetic."
          ],
          "items": [
            "Decide, in writing, which Shopify state matches the other system's sellable figure.",
            "Know which location the sync writes to, since each location has its own number.",
            "Some outside fulfilment services and dropshipping apps are themselves locations."
          ]
        },
        {
          "heading": "Set writes a final number; adjust writes a change",
          "body": [
            "Shopify offers two ways to change stock through its Admin API. An adjust mutation applies a relative change, a delta, so going from 100 to 102 sends a delta of two. A set mutation writes an absolute value, and Shopify states that it should only be used by a system that is the authoritative source for stock counts. Otherwise the adjust mutation is advised.",
            "The danger of an absolute write is timing. If the sync reads 100 from the other system, a customer buys two units in Shopify, and the sync then writes 100, the two sales are erased from Shopify's count and the item can be oversold. Shopify's set mutation guards against this with a comparison value: unless that check is skipped, the update goes through only if the stored quantity equals the value you supply. The documentation recommends always sending the comparison value and opting out only when necessary. In the current documentation version an idempotency key is also required, so a retried request can be recognised."
          ],
          "items": [
            "A spreadsheet sync that pastes absolute numbers has no comparison, which is the usual cause of \"sales disappeared\".",
            "Version specifics change; check the version of the API your integration calls."
          ]
        },
        {
          "heading": "What Shopify does not tell your sync",
          "body": [
            "Change notifications are not a complete feed. Shopify states that changes to committed, reserved, damaged, safety stock and quality control quantities do not fire webhooks, so an app that depends on those states must query for them. The general webhook guidance adds that delivery cannot be relied on every time, so a sync should not treat events as its only data source and should also run a periodic reconciliation that pulls current data.",
            "The product CSV is not a fix either: its inventory quantity column applies to single-location stores only, so using a spreadsheet import to correct stock on a multi-location store is the wrong tool."
          ],
          "items": []
        },
        {
          "heading": "A safe first investigation",
          "body": [
            "Pick three products that are wrong and write down, for each, the Shopify available quantity at the location the sync is meant to update, the committed quantity, and the other system's sellable figure. Then run the arithmetic before suspecting a fault."
          ],
          "items": [
            "Does available plus committed equal the other system's on-hand figure?",
            "Is the gap constant, or does it grow with each sync run?",
            "Does the gap match the number of open orders for that product?",
            "Is the sync writing to the same location that sells the product?",
            "Does the sync write absolute numbers or changes?"
          ]
        },
        {
          "heading": "What fixes it, and what does not fit",
          "body": [
            "Fixes change the rule, not the numbers: agree which system is authoritative, map each location, compare before writing or send changes instead of totals, and add a periodic reconciliation pass. A physical count, product-code clean-up across both systems, and a paid connector's internal bugs are outside a settings-and-logic fix; for a connector, send the reconciliation to the vendor."
          ],
          "items": []
        },
        {
          "heading": "How the paid fix is accepted",
          "body": [
            "The fixed job for this problem is accepted on a test store with a copy of your sync and a copy or sandbox of the other system, so nothing is written to your live systems. For the agreed products at the agreed location, Shopify available stock equals the other system's sellable figure under the written rule; a repeat run changes nothing; a test sale reduces both systems once; and when the copy is held between its read and its write, a sale placed in between is not overwritten. You apply the corrected logic to your live sync; we never receive store keys."
          ],
          "items": []
        }
      ],
      "incoming": [
        "example-store-stock-reconciliation-sheet",
        "guide-shopify-csv-import-handle-overwrite-blank-cells",
        "guide-store-reconciling-orders-and-stock-between-systems",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/shopify-inventory-locations-set-versus-adjust/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/shopify-inventory-locations-set-versus-adjust/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fshopify-inventory-locations-set-versus-adjust%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fshopify-inventory-locations-set-versus-adjust%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-store-reconciling-orders-and-stock-between-systems",
      "type": "guide",
      "title": "Reconciling a store's orders and stock with another system: a method that finds drift early",
      "description": "Why notification-based syncs miss or repeat events, and a reconciliation routine of two lists and a difference that works on any store platform.",
      "slug": "store-reconciling-orders-and-stock-between-systems",
      "url": "/guides/store-reconciling-orders-and-stock-between-systems/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Shopify developer documentation: Webhooks",
          "url": "https://shopify.dev/docs/apps/build/webhooks",
          "checked": "2026-10-11",
          "claims": [
            "Webhook delivery is not always guaranteed, and Shopify does not guarantee ordering within a topic.",
            "The page points to a header identifying a webhook delivery for ignoring duplicates, and to a triggered-at header or the payload's updated_at field for sorting events.",
            "Webhooks should not be the only data source: reconciliation jobs should periodically pull data from Shopify, and many GraphQL queries accept updated_at filters to fetch what changed since the last run."
          ]
        },
        {
          "label": "BigCommerce developer documentation: Webhooks overview",
          "url": "https://docs.bigcommerce.com/developer/docs/integrations/webhooks/overview.md",
          "checked": "2026-10-11",
          "claims": [
            "Duplicates may occasionally occur and can be handled with a temporary list of processed hash values.",
            "Payloads carry only an ID, so full details are fetched through the API.",
            "Retries last a cumulative 48 hours before a webhook is deactivated."
          ]
        },
        {
          "label": "Stripe documentation: Receive Stripe events in your webhook endpoint",
          "url": "https://docs.stripe.com/webhooks",
          "checked": "2026-10-11",
          "claims": [
            "Stripe does not guarantee delivery in the order events are generated, and duplicate deliveries should be identified by event ID.",
            "Missing objects can be retrieved through the API."
          ]
        },
        {
          "label": "Shopify developer documentation: Inventory management apps",
          "url": "https://shopify.dev/docs/apps/build/orders-fulfillment/inventory-management-apps",
          "checked": "2026-10-11",
          "claims": [
            "Changes to committed, reserved, damaged, safety stock and quality control quantities do not fire webhooks."
          ]
        }
      ],
      "related": [
        "store-keep-order-inventory-sync-healthy",
        "inventory-shopify-stock-out-of-step-with-connected-system",
        "bigcommerce-order-webhook-deactivated-orders-not-syncing",
        "example-store-stock-reconciliation-sheet",
        "guide-bigcommerce-webhook-retries-deactivation",
        "guide-shopify-inventory-locations-set-versus-adjust",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "sections": [
        {
          "heading": "Three ways a sync goes wrong without telling anyone",
          "body": [
            "A store and another system, say a warehouse tool or accounting package, usually stay in step through notifications: the store says an order was placed, a stock level changed, and the other system reacts. The platform documentation for each of the three we cover says that this is not a perfect channel. Shopify says webhook delivery cannot be relied on every time and that events may arrive out of order. BigCommerce warns that duplicates occasionally occur and deactivates a webhook after retries run out. Stripe says events may arrive in a different order from the one they were generated in, and that duplicate deliveries happen. A sync that only listens will eventually be wrong without any error.",
            "The three failure families are different and need different checks. Missed events leave the other system without an order or a stock change. Duplicated or reordered events create two records, or apply an older change after a newer one. Wrong-state writes put a number in that was right when read and wrong when written, such as an absolute stock level that erases a sale."
          ],
          "items": [
            "Missed: something exists in the store and not in the other system.",
            "Repeated or reordered: something exists twice, or in the wrong state.",
            "Overwritten: both exist, but a number is wrong."
          ]
        },
        {
          "heading": "The method: two lists and a difference",
          "body": [
            "Reconciliation does not need to be clever. Take the identifiers from both systems for the same window, compare them, and look at what is on one list and not the other. For orders, use the order number or ID and the creation time. For stock, use the product code, the location and the figure for the same state. Do it on a schedule, daily for orders and weekly for a stock sample is a sensible start, and treat any unexplained difference as the finding.",
            "Shopify's guidance for app builders is the same idea: do not treat webhooks as your only data source; run reconciliation jobs that periodically pull data, and use the updated_at filter on queries to fetch what changed since the last run. A reconciliation does not replace the notification path. It catches what the notification path loses."
          ],
          "items": [
            "Name the authoritative system for each kind of data before comparing.",
            "Compare the same window and the same state of stock on both sides.",
            "Record counts as well as lists; a missing export should read as unverified, not as a pass."
          ]
        },
        {
          "heading": "Handling repeats and ordering",
          "body": [
            "The receiving side should assume repeats and disorder. Keep a record of the identifier of each delivery, Shopify's delivery header, BigCommerce's hash or Stripe's event ID, and ignore one you have already processed. Do not rely on arrival order. Shopify suggests sorting by its triggered-at header or the payload's updated_at, and BigCommerce and Stripe both lean on fetching the current object from the API when the notification is light or arrives early. The rule that follows: read the current state when you act, rather than trusting what the notification said when it was sent."
          ],
          "items": []
        },
        {
          "heading": "Stock needs one extra rule",
          "body": [
            "Stock changes can be missed by design. Shopify states that changes to committed, reserved, damaged, safety stock and quality control quantities do not fire webhooks, so an app that depends on those states has to query for them. And a stock figure is only comparable if both systems mean the same thing by it: available, on hand, or on hand minus committed. Write the mapping down. Where the sync writes numbers, prefer sending changes, or comparing before writing, to overwriting with a total."
          ],
          "items": []
        },
        {
          "heading": "Closing a gap once you find one",
          "body": [
            "A gap list is the practical output: every order or product that is on one side only, with its time. Load the missing items into the other system by a route you control, then re-run the comparison and expect zero. Fix the cause before replaying anything, or the same notification path will lose the same events again. BigCommerce's documentation describes retries lasting 48 hours and then deactivation; it does not describe replaying missed events, so compare the order lists and load the gap from the store's own order records."
          ],
          "items": []
        },
        {
          "heading": "A safe first check you can do today",
          "body": [
            "You can try the method on one week of data without touching either system. Export the order numbers for the same recent week from the store and from the other system, put them in two columns, and mark every number that appears in only one of them. Then pick three products, write down the stock figure each system holds for the same state, and note any that differ. Nothing in either system is changed, and a gap you find is a lead to explain, not yet a fault."
          ],
          "items": [
            "Use the same week and the same time zone on both sides.",
            "Count the rows in each export first; an export that stops early looks like a gap.",
            "Write down which system you treat as correct before comparing."
          ]
        },
        {
          "heading": "What this does not cover, and how it becomes a service",
          "body": [
            "A comparison tells you where the numbers differ, not what the true stock is; a physical count is yours. It also does not change either system. The one-off fixes for a drifting stock sync and a deactivated order webhook use this method, and the standing service runs the comparison every week and explains up to two separate causes of difference a month, with a monthly summary. The correction itself stays the one-off job. You apply every change to your live systems."
          ],
          "items": []
        },
        {
          "heading": "How the paid work is accepted",
          "body": [
            "The fixed stock job is accepted on a test store with copies of your sync and of the other system: the agreed products match under the written rule, a repeat run changes nothing, a test sale reduces both once, and a held sync does not overwrite a sale placed in the middle of its run. The fixed order-webhook job is accepted on synthetic notifications to a copy of your receiver, with a list of the orders in the missed window. The standing service is accepted on a planted difference in a copy of the first exports being found, on each weekly result listing every order on one side only and every stock difference above the threshold, on a written explanation for each cause within the monthly allowance of two, and on a monthly summary. It changes nothing in your systems."
          ],
          "items": []
        }
      ],
      "platforms": [
        "bigcommerce"
      ],
      "incoming": [
        "example-store-stock-reconciliation-sheet",
        "guide-shopify-inventory-locations-set-versus-adjust",
        "guide-bigcommerce-webhook-retries-deactivation",
        "platform-bigcommerce",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/store-reconciling-orders-and-stock-between-systems/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/store-reconciling-orders-and-stock-between-systems/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fstore-reconciling-orders-and-stock-between-systems%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fstore-reconciling-orders-and-stock-between-systems%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-store-catalogue-move-option-variant-limits",
      "type": "guide",
      "title": "Moving a WooCommerce or Magento catalogue to Shopify: how options and variants map",
      "description": "How parent and variation rows in a WooCommerce or Magento export become Shopify handles and variant rows, and where the models disagree.",
      "slug": "store-catalogue-move-option-variant-limits",
      "url": "/guides/store-catalogue-move-option-variant-limits/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Shopify Help Center: Product CSV file format",
          "url": "https://help.shopify.com/en/manual/products/import-export/using-csv",
          "checked": "2026-10-11",
          "claims": [
            "A product can have up to three options, and a single-option product uses Default Title.",
            "Each variant row repeats the handle and leaves title, description, vendor and tags empty.",
            "Images are one per row, up to 250 per product.",
            "The handle is the unique product identifier, it allows letters, numbers and dashes, and it is required when adding variants or updating products.",
            "Barcodes allow up to 20 values and tags up to 250 per product."
          ]
        },
        {
          "label": "Shopify Help Center: Importing products with a CSV file",
          "url": "https://help.shopify.com/en/manual/products/import-export/import-products",
          "checked": "2026-10-11",
          "claims": [
            "The maximum file size is 15 MB, so large files are split.",
            "Shopify recommends testing large imports on a development store.",
            "Headers are case sensitive and missing or mismatched headers cause the import to fail."
          ]
        },
        {
          "label": "Shopify Help Center: Migrating to Shopify",
          "url": "https://help.shopify.com/en/manual/migrating-to-shopify",
          "checked": "2026-10-11",
          "claims": [
            "Products can move by CSV or a migration app, and products should be imported first, then customers, then historical orders.",
            "A product missing a variant option will not import and has to be added manually, and imported products can arrive hidden.",
            "Shopify's URL structure differs, so old links to specific pages likely will not load."
          ]
        },
        {
          "label": "WooCommerce documentation: Product CSV Importer and Exporter",
          "url": "https://woocommerce.com/document/product-csv-importer-exporter/",
          "checked": "2026-10-11",
          "claims": [
            "A variable parent row has Type variable and lists every attribute value; each variation row has Type variation, a unique SKU, an empty ID, one attribute value and a Parent value.",
            "Images are a comma-separated list of URLs, and the first becomes the featured image."
          ]
        },
        {
          "label": "Adobe Commerce documentation: Import configurable products",
          "url": "https://experienceleague.adobe.com/en/docs/commerce-admin/systems/data-transfer/examples/data-transfer-configurable-products",
          "checked": "2026-10-11",
          "claims": [
            "The export has one row for the configurable product and a separate row for each simple-product variation, and the product type column tells them apart.",
            "The configurable variations column links the parent row to its children, with entries divided by a pipe and attributes within an entry divided by commas, using attribute codes rather than labels."
          ]
        },
        {
          "label": "Adobe Commerce documentation: Export data",
          "url": "https://experienceleague.adobe.com/en/docs/commerce-admin/systems/data-transfer/data-export",
          "checked": "2026-10-11",
          "claims": [
            "Products are exported from System, Data Transfer, Export, as CSV, and the export runs in the background through a queue that needs cron to be running."
          ]
        },
        {
          "label": "Shopify Help Center: Add variants",
          "url": "https://help.shopify.com/en/manual/products/variants/add-variants",
          "checked": "2026-10-11",
          "claims": [
            "A product can have up to 2,048 variants and up to three options.",
            "Some third-party themes, theme app extensions, public apps, sales channels and custom apps might not support more than 100 variants."
          ]
        }
      ],
      "related": [
        "store-catalogue-mapping-to-shopify-csv",
        "platform-shopify",
        "platform-magento",
        "platform-wordpress-woocommerce",
        "guide-store-redirects-and-launch-checks-after-replatform",
        "guide-shopify-csv-import-handle-overwrite-blank-cells",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "sections": [
        {
          "heading": "Two models of the same product",
          "body": [
            "WooCommerce and Magento describe a product with options as a parent plus separate child records. Shopify describes it as one product, identified by its handle, with variants as repeated rows that carry the same handle. The first row holds the product's own fields; every later row for that product repeats the handle, leaves title, description, vendor and tags empty, and fills in the variant details and one image. A single-option product still needs a placeholder option name and value, and Shopify uses Default Title for that case.",
            "Moving a catalogue is therefore a reshaping job, not a copy. Each parent and its children collapse into one handle with several rows, and each attribute becomes an option with a name and values."
          ],
          "items": [
            "One Shopify product per parent; one row per variant.",
            "Option names and values come from the source attributes.",
            "Every file column needs Shopify's exact header names, which are case sensitive."
          ]
        },
        {
          "heading": "Reading a WooCommerce export",
          "body": [
            "In the WooCommerce product export the parent row has the type variable and lists every attribute value. Each variation row has the type variation, its own SKU, an empty ID, a single attribute value, and a Parent value that names the parent by SKU or ID. Attribute names and values in the variation rows are meant to agree with the parent, which is the first thing to check. Images come as a comma-separated list of URLs with the first as the featured image, which maps neatly to Shopify's one-image-per-row layout, with the order recorded as a position."
          ],
          "items": [
            "Group variation rows under their parent by the Parent value.",
            "Check that every variation's attribute values are ones the parent lists.",
            "A blank variation attribute means any value, which Shopify has no equivalent for."
          ]
        },
        {
          "heading": "Reading a Magento or Adobe Commerce export",
          "body": [
            "The Adobe Commerce export, taken from System, Data Transfer, Export as CSV, has one row for the configurable product and a row for each simple product, and a product type column tells them apart. The parent row's configurable variations column links it to its children: each entry is a SKU followed by attribute and value pairs, entries are separated by a pipe, and the attributes inside an entry are separated by commas, using attribute codes rather than display labels. Because commas separate the attributes, a value that contains a comma needs careful handling, and any such value should be inspected by hand. Adobe notes that the export runs in the background through a queue and that your cron job needs to be running, so if the file never appears, check that cron is running."
          ],
          "items": [
            "Translate attribute codes back into the names a shopper should see.",
            "Check values that contain commas, pipes or quotes by eye.",
            "Make sure each simple product ends up as exactly one variant row."
          ]
        },
        {
          "heading": "Where the models disagree, and what you must decide",
          "body": [
            "Shopify allows up to three options and up to 2,048 variants per product. Products near or over 100 variants need a decision too, because Shopify says some third-party themes, apps and sales channels might not support more than 100 variants; check which of yours do before you build the file. Count the variants of every source product before building anything: three attributes with several values each multiply quickly. If a source product uses four attributes, someone must choose: merge two attributes into one option, such as colour and finish, or split the product into several. A product missing a variant option will not import at all, according to Shopify's migration guidance, so these cases cannot be left to chance. Smaller limits to design around: up to 250 images per product, up to 250 tags, up to 20 barcodes, and handles that must be unique, using only letters, numbers and dashes.",
            "Other source concepts have no direct equivalent: a blank \"any\" attribute, product types that carry custom fields, grouped products and categories that are not collections. Each needs a stated rule in a mapping sheet, so the result is repeatable and reviewable."
          ],
          "items": [
            "List every product with more than 100 variants, and every one over 2,048, before building anything.",
            "List every product with more than three options before building anything.",
            "Decide the rule for each unmatched concept in writing.",
            "Keep a list of items excluded on purpose."
          ]
        },
        {
          "heading": "Prove it before it touches the real store",
          "body": [
            "Shopify recommends testing large imports on a development store, and the file limit is 15 MB, so large catalogues are split. Import on the test store, export again, and compare counts and a sample of products with the source. Imported products can arrive hidden, and the migration guidance says to import products first, then customers, then historical orders so that orders link to the right products. When the test comparison is clean, the same files can be imported on the live store by its owner, after a fresh export as a safety copy."
          ],
          "items": [
            "Compare product and variant counts, not just a few pages.",
            "Include every product with options in the sample.",
            "Check image counts and the first image of each product."
          ]
        },
        {
          "heading": "How the paid work is accepted",
          "body": [
            "The fixed job for this problem builds the mapping, the Shopify product file and a redirect file, and is accepted when the test store shows the same number of products and variants as the source, twenty sampled products match in title, options, SKU, price and image count, the import shows no row errors, and every redirect target is a product that exists. The wider project adds a comparison of the live store after your own import and the launch checks you choose. Customers, orders, themes and payments are outside both."
          ],
          "items": []
        }
      ],
      "platforms": [
        "magento"
      ],
      "incoming": [
        "guide-shopify-csv-import-handle-overwrite-blank-cells",
        "guide-store-redirects-and-launch-checks-after-replatform",
        "guide-woocommerce-variation-attributes-and-any",
        "guide-magento-indexers-schedule-cron-triggers",
        "platform-magento",
        "buyer-store-owner-moving-platforms",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/store-catalogue-move-option-variant-limits/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/store-catalogue-move-option-variant-limits/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fstore-catalogue-move-option-variant-limits%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fstore-catalogue-move-option-variant-limits%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-store-redirects-and-launch-checks-after-replatform",
      "type": "guide",
      "title": "Redirects and launch checks when you move a store to Shopify",
      "description": "How old product addresses are redirected, the rule that stops a redirect working, the order of work, and the checks to run before switching a domain.",
      "slug": "store-redirects-and-launch-checks-after-replatform",
      "url": "/guides/store-redirects-and-launch-checks-after-replatform/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Shopify Help Center: URL redirects",
          "url": "https://help.shopify.com/en/manual/online-store/menus-and-links/url-redirect",
          "checked": "2026-10-11",
          "claims": [
            "Redirects are created in the Shopify admin with Redirect from and Redirect to fields, and can be bulk-imported from a CSV, using a downloadable sample for the layout.",
            "A store can have up to 100,000 redirects.",
            "Some paths cannot be redirected, including those beginning with apps, cart, orders, services or shop.",
            "A redirect works only from a URL that does not load a valid page, so a page that still loads must be hidden or deleted so it returns a 404.",
            "A destination outside the primary domain needs a full URL, and a relative URL is used inside the domain."
          ]
        },
        {
          "label": "Shopify Help Center: Migrating to Shopify",
          "url": "https://help.shopify.com/en/manual/migrating-to-shopify",
          "checked": "2026-10-11",
          "claims": [
            "Shopify's URL structure differs from other platforms, so old links to specific pages likely will not load for customers.",
            "Set up URL redirects before moving the domain, covering bookmarked pages and third-party links, and after launch check that the most-visited old URLs reach the right new pages.",
            "You may need to disconnect the domain from the old platform first to avoid SSL certificate errors.",
            "Post-import checks cover price, weight, inventory, descriptions and images, and test orders should cover successful and failed payments, refunds, cancellations, fulfilment and the emails each step generates.",
            "Importing orders triggers a new-order email to each staff member who gets those notifications."
          ]
        }
      ],
      "related": [
        "store-catalogue-mapping-to-shopify-csv",
        "platform-shopify",
        "guide-store-catalogue-move-option-variant-limits",
        "buyer-store-owner-moving-platforms",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "sections": [
        {
          "heading": "Why old addresses need a plan",
          "body": [
            "Every product page on the old store has an address that customers, bookmarks, emails and other sites still use. Shopify builds its addresses differently, so Shopify's own migration guidance says old links to specific pages likely will not load. A redirect tells a visitor who arrives at an old address where the page now lives. Without redirects, every old link becomes a dead end, and the people who use them are your most loyal visitors."
          ],
          "items": [
            "Redirects cover bookmarks, emails and links from other sites.",
            "No redirect file can promise a search ranking outcome."
          ]
        },
        {
          "heading": "Building the redirect list",
          "body": [
            "A redirect has two fields: the address to redirect from and the address to redirect to. Shopify lets you create them one at a time or import a CSV, and offers a sample file for the exact layout, so use that file rather than guessing headers. A destination inside your domain is entered as a relative address, and a destination elsewhere needs the full address. A store can have up to 100,000 redirects.",
            "The list comes from the old store. Export the product addresses, work out the handle each product has in the new store, and pair them. Each pair should be reviewed by a person who knows the products, because a redirect to the wrong product is worse than none. Collections, pages and blog posts need their own pairs if you want them redirected."
          ],
          "items": [
            "One old address to one new address.",
            "Check every target is a handle that exists on the new store.",
            "Some paths, such as those beginning with cart or orders, cannot be redirected."
          ]
        },
        {
          "heading": "The rule that makes a correct redirect do nothing",
          "body": [
            "A Shopify redirect works only from an address that does not load a valid page. If the old address still loads something on the new store, the redirect is ignored. Shopify says that to make an address eligible you can hide or delete the page so that it returns a 404. This can happen when a new product happens to have the same handle as an old one, or when a hidden collection is made visible again, in which case its redirect is removed automatically."
          ],
          "items": []
        },
        {
          "heading": "Order of work",
          "body": [
            "Shopify's guidance gives a sequence that avoids the common problems. Import products first, then customers, then historical orders, so that orders connect to the right products and customers; importing orders sends a new-order email to each staff member who receives those notifications, so turn them off temporarily. Set up redirects before moving the domain. You may also need to disconnect the domain from the old platform first to avoid certificate errors. Keep the old store available until the checks pass."
          ],
          "items": [
            "Products, then customers, then orders.",
            "Redirects before the domain moves.",
            "Switch off staff order emails during an order import."
          ]
        },
        {
          "heading": "Launch checks that catch real problems",
          "body": [
            "After products are imported, check price, weight, inventory, descriptions and images on a sample that includes every product with options. Then place test orders that cover successful and failed payments, refunds, cancellations, and full and partial fulfilment, and read the customer emails each step produces. After launch, test the most visited old addresses and record where each one lands. If you want search engines to learn the new structure, submit a sitemap; no result is promised."
          ],
          "items": [
            "Record the destination of each tested old address, not just pass or fail.",
            "Run the failed-payment and refund cases, not only the happy path.",
            "Check the emails, not only the screens."
          ]
        },
        {
          "heading": "What does not fit, and how it is accepted",
          "body": [
            "Domain transfers, theme design, payment and tax setup, customers and historical orders are separate pieces of work. In the paid catalogue move project, you run the live import and the redirect import; we then compare a product export from your live store with the source and record the redirect results you send us. It is accepted when counts and sampled products match, the redirect results show the intended destination each time, and you accept the launch checklist."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-store-catalogue-move-option-variant-limits",
        "buyer-store-owner-moving-platforms",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/store-redirects-and-launch-checks-after-replatform/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/store-redirects-and-launch-checks-after-replatform/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fstore-redirects-and-launch-checks-after-replatform%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fstore-redirects-and-launch-checks-after-replatform%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-woocommerce-variation-attributes-and-any",
      "type": "guide",
      "title": "Why a WooCommerce variable product loses choices: attributes, imports and the \"Any\" option",
      "description": "How WooCommerce builds the size and colour choices a shopper sees, what breaks them after an import or edit, and how to test each combination.",
      "slug": "woocommerce-variation-attributes-and-any",
      "url": "/guides/woocommerce-variation-attributes-and-any/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "WooCommerce documentation: Variable products",
          "url": "https://woocommerce.com/document/variable-product/",
          "checked": "2026-10-11",
          "claims": [
            "Attributes are defined on the Attributes tab and must be saved before variations are created; changing attributes after variations exist may mean redoing the variations.",
            "Variations are generated in bulk or added manually, and each can carry its own SKU, price, stock settings and image, with blank SKU, weight and dimensions falling back to the parent.",
            "Choosing \"Any\" for an attribute makes variations that can effectively duplicate each other, WooCommerce uses the first match from the top of the list, and the page recommends defining every attribute on every variation.",
            "Variations without prices do not show in the store.",
            "Products with 30 or fewer variations get dynamic dropdowns; above that the dropdowns are static and an invalid pick shows a message that no products matched the selection.",
            "Stock can be tracked on the product, on the variation or both, and a variation without its own tracking draws from product-level stock if that is enabled."
          ]
        },
        {
          "label": "WooCommerce documentation: Product CSV Importer and Exporter",
          "url": "https://woocommerce.com/document/product-csv-importer-exporter/",
          "checked": "2026-10-11",
          "claims": [
            "In the product CSV the parent row has Type variable and lists every attribute value, and each variation row has Type variation, a unique SKU, an empty ID, one attribute value and a Parent value.",
            "Attribute names and values in variation rows must agree with the parent.",
            "A blank variation attribute means any value.",
            "With the update option ticked, rows are matched to existing products by ID or SKU."
          ]
        }
      ],
      "related": [
        "woo-variable-product-variations-not-selectable",
        "platform-wordpress-woocommerce",
        "guide-woocommerce-update-test-order-script",
        "guide-store-catalogue-move-option-variant-limits",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "sections": [
        {
          "heading": "How WooCommerce builds the choices a shopper sees",
          "body": [
            "A variable product is a parent with a set of attributes, such as size and colour, and a list of variations. Each variation is a combination of attribute values with its own price, SKU and stock settings. The shopper's dropdowns come from the attributes saved on the parent, and the product page then looks for the variation that matches the chosen values. If it finds one with a price, the choice can be added to the cart. If it does not, the shopper sees that the choice is unavailable.",
            "Two rules matter more than they look. First, attributes must be saved on the parent before variations are made, and changing attributes later can mean redoing the variations. Second, a variation without a price does not show in the store, however much stock it has."
          ],
          "items": [
            "The parent decides which values can be offered; a variation can only use values the parent lists.",
            "A variation with no price is invisible to shoppers.",
            "A blank SKU, weight or dimensions on a variation falls back to the parent's value."
          ]
        },
        {
          "heading": "How an import breaks the match between parent and variation",
          "body": [
            "WooCommerce's CSV import describes variable products in two kinds of row. The parent row has the type variable and lists every attribute value. Each variation row has the type variation, a unique SKU, an empty ID, one attribute value, and a Parent value naming the parent by SKU or ID. The attribute names and values in the variation rows must agree with those on the parent. A variation whose colour reads \"Navy Blue\" when the parent lists \"Navy\" is not a match, and the combination cannot be selected.",
            "Updates add a second risk. With the update option ticked, rows are matched to existing products by ID or SKU, so a changed SKU creates a new product instead of updating the old one. A blank variation attribute is read as \"any value\", which turns an exact variation into a wildcard. Whether an empty cell keeps or erases other stored values is not stated in general by WooCommerce, so test one product before importing many."
          ],
          "items": [
            "Compare one variation row with its parent row, character by character.",
            "Look for variations that share a SKU, or an empty Parent value.",
            "Check that a blank attribute cell is intended."
          ]
        },
        {
          "heading": "The \"Any\" option and the order WooCommerce matches in",
          "body": [
            "Choosing \"Any\" for an attribute on a variation is a convenience that makes a variation apply to every value of that attribute. WooCommerce warns it can make variations effectively duplicate each other, and it uses the first match from the top to the bottom of the variation list in the admin. A broad variation above a specific one wins, so the specific price never appears. The documentation recommends defining every attribute on every variation, and if \"Any\" is used, tracking stock on the product, keeping prices uniform and testing thoroughly."
          ],
          "items": [
            "Order variations from most specific to least specific if \"Any\" is used.",
            "Prefer explicit values on every variation for products with different prices per option."
          ]
        },
        {
          "heading": "Stock settings and the 30-variation switch",
          "body": [
            "Stock can be tracked on the product, on each variation, or on a mix. An out-of-stock variation disappears from the dropdown only when several settings line up: hiding is on, stock is tracked per variation, the quantity is zero or the status is out of stock, and backorders are off. Otherwise an unavailable combination still appears and shows an unavailable or out-of-stock message.",
            "There is also a size limit on behaviour. Products with 30 or fewer variations get dynamic dropdowns that only offer valid combinations. Above 30, the dropdowns are static and an invalid pick shows a message that no products matched the selection. A product that grew past 30 variations can therefore start showing that message for combinations that never existed, without anything being broken."
          ],
          "items": []
        },
        {
          "heading": "A safe first investigation on a copy",
          "body": [
            "Work on a staging copy, never on the live product. Write down the combinations that should exist and the price you expect for each, then open the Variations tab and compare."
          ],
          "items": [
            "Count the variations and compare with the combinations you listed.",
            "Open one failing variation: is the price empty, is it enabled, are attribute values the exact ones the parent lists?",
            "Look for \"Any\" choices and check their position in the list.",
            "Add each listed combination to the cart and note which variation is added.",
            "If the product came from an import, open the import file and compare the parent row and a failing variation row."
          ]
        },
        {
          "heading": "What fixes it, and what does not fit",
          "body": [
            "Fixes are data and settings: correct the attribute values, add missing prices, re-order variations, or correct the file and re-import on the copy with a test of one product first. A swatch plugin, a bundle plugin or a plugin that generates variations may own the behaviour; if it cannot be tested on a copy, a fixed repair of one product will not fit. Redesigning the selector or the page is design work, not a data repair."
          ],
          "items": []
        },
        {
          "heading": "How the paid fix is accepted",
          "body": [
            "The fixed job for this problem is accepted on a staging copy. Every combination you agreed can be selected and adds exactly one matching variation to the cart, each shows the expected price, combinations that should not exist cannot be selected, stock behaves as agreed for one in-stock and one out-of-stock combination, and an unrelated variable product still works. Your site holder applies the change to the live store."
          ],
          "items": []
        }
      ],
      "incoming": [
        "collection-store-checkout-order-flow-diagnosis",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/woocommerce-variation-attributes-and-any/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/woocommerce-variation-attributes-and-any/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fwoocommerce-variation-attributes-and-any%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fwoocommerce-variation-attributes-and-any%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-woocommerce-shipping-zone-order-and-postcodes",
      "type": "guide",
      "title": "Why WooCommerce shows no shipping for an address you serve: zone order and postcode entries",
      "description": "How WooCommerce picks one shipping zone per address, why zone order matters and how postcode patterns decide who gets which shipping method.",
      "slug": "woocommerce-shipping-zone-order-and-postcodes",
      "url": "/guides/woocommerce-shipping-zone-order-and-postcodes/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "WooCommerce documentation: Setting up shipping zones",
          "url": "https://woocommerce.com/document/setting-up-shipping-zones/",
          "checked": "2026-10-11",
          "claims": [
            "Each customer matches only one zone, based on the shipping address, and sees only that zone's methods.",
            "WooCommerce checks zones from the top of the list down and the first match wins, so zones should be ordered from smallest area to largest.",
            "From WooCommerce 11.1 the zones table warns when an earlier, broader zone makes a later zone unreachable.",
            "A catch-all zone called Rest of the world applies to anyone who matches no other zone and cannot be moved, renamed or deleted.",
            "Flat rate, free shipping and local pickup are built in, and a missing method probably comes from a third-party extension or custom code.",
            "A customer whose address falls in a zone with no methods is told that no shipping is available.",
            "Postcode entries go one per line and can be exact codes, numeric ranges or wildcards with an asterisk, and wildcards inside numeric ranges are not supported.",
            "The Shipping location settings under WooCommerce settings, General, are a prerequisite."
          ]
        }
      ],
      "related": [
        "woo-no-shipping-options-for-destination",
        "platform-wordpress-woocommerce",
        "collection-store-checkout-order-flow-diagnosis",
        "guide-woocommerce-update-test-order-script",
        "guide-woocommerce-checkout-conflicts"
      ],
      "sections": [
        {
          "heading": "One address, one zone, first match wins",
          "body": [
            "WooCommerce does not combine zones. For each shipping address it checks the zone list from the top down, takes the first zone that matches, and offers only the methods inside that zone. If the zone it picks has no methods, the shopper is told no shipping is available, even when a perfectly good zone sits lower in the list. A zone can be defined by countries, states or provinces, continents or postcodes.",
            "This is why the order of the list is the first thing to read. The documented advice is to put zones from the smallest area to the largest: city before state, state before country. A broad zone placed above a narrower one captures the addresses the narrower one was meant to serve. From WooCommerce 11.1 the zones table warns you when an earlier, broader zone makes a later zone unreachable, so on that version or later look for the warning before anything else."
          ],
          "items": [
            "Read the zones from top to bottom as WooCommerce does.",
            "For each failing address, find the first zone that could match it.",
            "Look at that zone, not the one you expected: does it have methods?"
          ]
        },
        {
          "heading": "The fallback zone and the empty zone",
          "body": [
            "Every store has a catch-all zone named Rest of the world. It applies to anyone who matches no other zone, adding methods to it is optional, and it cannot be moved, renamed or deleted. If you want to exclude some regions while still using the catch-all, the documentation says to create a zone for those regions and give it no methods. That works as designed, and it is also a common accident: a zone created to exclude a region, or left half-finished, with no methods catches addresses and gives shoppers nothing."
          ],
          "items": [
            "A zone that exists but has no methods is a valid state that produces \"no shipping\".",
            "The three built-in methods are flat rate, free shipping and local pickup; anything else comes from an extension."
          ]
        },
        {
          "heading": "How postcode entries match",
          "body": [
            "Postcode limits are written one per line. WooCommerce accepts exact codes, numeric ranges written with an ellipsis, and wildcards with an asterisk. A wildcard matches everything that starts the same way, and it is the recommended form for postcodes that contain letters: an entry such as CB23 followed by an asterisk matches CB23 1EX. Wildcards inside numeric ranges are not supported, so a pattern that mixes the two silently matches less than you expect.",
            "Because postcode entries decide which zone an address lands in, test addresses just inside and just outside each pattern. An entry that is a character too long or too short can exclude the very area it was written for."
          ],
          "items": [
            "One entry per line; no commas.",
            "Use a wildcard for postcodes with letters.",
            "Do not put a wildcard inside a numeric range."
          ]
        },
        {
          "heading": "The setting that sits outside the zones",
          "body": [
            "Before any zone is consulted, the store-wide shipping location settings under the General settings decide which countries can reach checkout at all. If a country is not allowed to ship to there, no zone setup can offer it a method. Documentation lists this check as the prerequisite for zone work, and it is the quickest to read."
          ],
          "items": []
        },
        {
          "heading": "A safe first investigation on a copy",
          "body": [
            "Use a staging copy with payments in test mode. Make a table of the destinations you serve and the method and cost each should show. Run every address to the checkout total and record the methods shown."
          ],
          "items": [
            "Test one address inside each zone, one just outside, and one in the catch-all.",
            "Include an address that worked before and one that never did.",
            "Check the selling and shipping location settings for each failing country.",
            "If a method you expect is missing, check whether it came from an extension."
          ]
        },
        {
          "heading": "What fixes it, and what does not fit",
          "body": [
            "Fixes are ordering, entries and methods: reorder zones from smallest to largest, add the method to an empty zone, correct the postcode patterns, or allow the country in the store settings. Live courier-rate plugins, table-rate plugins and their accounts are different integrations; if those own the missing rate, this fixed repair will not fit. Choosing what to charge is your decision."
          ],
          "items": []
        },
        {
          "heading": "How the paid fix is accepted",
          "body": [
            "The fixed job for this problem is accepted on a staging copy. Each agreed destination shows exactly the methods and costs in your confirmed table at the checkout total, a destination you do not serve shows no method, a destination that worked before still gives the same result, and the final zone order matches the written settings. Your site holder applies the settings to the live store."
          ],
          "items": []
        }
      ],
      "incoming": [
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/woocommerce-shipping-zone-order-and-postcodes/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/woocommerce-shipping-zone-order-and-postcodes/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fwoocommerce-shipping-zone-order-and-postcodes%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fwoocommerce-shipping-zone-order-and-postcodes%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-woocommerce-pending-payment-gateway-confirmation",
      "type": "guide",
      "title": "WooCommerce orders stuck on Pending payment after the customer paid: where the confirmation is lost",
      "description": "How a payment confirmation reaches WooCommerce, the status each failure leaves, and a safe way to find where it stops without touching live payments.",
      "slug": "woocommerce-pending-payment-gateway-confirmation",
      "url": "/guides/woocommerce-pending-payment-gateway-confirmation/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "WooCommerce documentation: Order statuses",
          "url": "https://woocommerce.com/document/managing-orders/order-statuses/",
          "checked": "2026-10-11",
          "claims": [
            "Pending payment means the order exists but no payment has arrived; Processing means paid with stock deducted; On hold means payment is not yet confirmed though stock is deducted.",
            "Failed and Cancelled orders return stock to inventory.",
            "With the Hold Stock setting enabled, WooCommerce cancels eligible Pending payment orders created through checkout once the configured time limit passes."
          ]
        },
        {
          "label": "WooCommerce Stripe extension: Setting up webhooks",
          "url": "https://woocommerce.com/document/stripe/setup-and-configuration/stripe-webhooks/",
          "checked": "2026-10-11",
          "claims": [
            "The Stripe extension sends requests to Stripe through its API, but Stripe can only reach the extension through webhooks.",
            "The extension uses endpoints of the form the site address followed by a query for the wc-api wc_stripe route.",
            "From version 8.6.1 webhooks are created automatically when the extension connects to Stripe, and they can be recreated with a Reconfigure webhooks action on the Live and Test tabs.",
            "Both tabs should show the status Configured, and the account details show whether webhooks are being processed successfully."
          ]
        },
        {
          "label": "Stripe documentation: Receive Stripe events in your webhook endpoint",
          "url": "https://docs.stripe.com/webhooks",
          "checked": "2026-10-11",
          "claims": [
            "A webhook endpoint must quickly return a 2xx status before complex logic.",
            "Stripe treats redirect responses as failures, and access restrictions or a missing URL appear as 4xx statuses.",
            "In live mode Stripe attempts delivery for up to three days with exponential back off, and in a sandbox it retries three times over a few hours.",
            "The Event deliveries tab lists events as Delivered, Pending or Failed with the HTTP status code.",
            "Events can be resent from the Dashboard for up to 15 days, and a manual resend does not cancel automatic retries.",
            "Duplicate deliveries should be identified by event ID, and ordering is not guaranteed."
          ]
        }
      ],
      "related": [
        "woo-orders-stuck-pending-after-payment",
        "platform-wordpress-woocommerce",
        "platform-stripe",
        "guide-stripe-webhook-delivery",
        "woocommerce-checkout-after-update",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "sections": [
        {
          "heading": "What each status tells you",
          "body": [
            "WooCommerce's order statuses are a short story about what the store knows. Pending payment means the order exists but no payment has arrived. Processing means the order is paid and stock has been deducted. On hold means payment is not yet confirmed, although stock is already deducted; that is expected for offline methods and delayed-notification methods. Failed means the payment was declined or did not go through, and stock goes back. So an order that stays Pending payment, or sits On hold for a method that should confirm within minutes, tells you the store has not heard what happened to the money.",
            "There is a further consequence. With the Hold Stock setting enabled, WooCommerce cancels eligible Pending payment orders created through checkout once the time limit passes. If the confirmation never arrived, a customer who did pay can end up with a cancelled order. That is why the delay matters, and why a list of paid-but-pending orders is worth building quickly."
          ],
          "items": [
            "Pending payment: the store has no payment yet.",
            "On hold: not confirmed, stock reserved.",
            "Cancelled by Hold Stock: a risk for paid orders whose confirmation was lost."
          ]
        },
        {
          "heading": "How the confirmation travels",
          "body": [
            "For many payment methods the customer is sent away to pay and returns to the store, but the reliable signal comes separately, from the payment provider to the store, as a webhook. The WooCommerce Stripe extension states it directly: it sends requests to Stripe through the API, but Stripe can only reach the extension through webhooks. If that second path is broken, payments succeed at Stripe while the order never changes. The extension's endpoint carries a wc-api route on your site address, and from version 8.6.1 the webhooks are created automatically when the extension connects.",
            "Other gateways differ in detail but follow the same pattern: a notification from the provider to an address on your site, and a status change in WooCommerce when it arrives. If your gateway is not Stripe, read its documentation for the equivalent."
          ],
          "items": []
        },
        {
          "heading": "Where the confirmation can be lost",
          "body": [
            "Stripe's documentation gives a table of what a failed delivery looks like, and each row maps to a cause on the store side. Redirects count as failures, so an address that redirects from the bare domain to the www version, or from http to https, fails every time. Access restrictions and missing URLs appear as 4xx statuses, which is how a security plugin, firewall rule or password-protected staging site shows up. Connection and TLS errors point at the host or the certificate, and a timeout means the site was too slow to answer. Stripe expects a quick 2xx before any heavy work.",
            "Anything that changes the site's address, such as a domain change, a move to https or a copy of the site, can leave the provider pointing at the old address. Deleting the webhook in the provider dashboard has the same effect."
          ],
          "items": [
            "Redirects on the webhook address count as failures.",
            "4xx statuses point at access rules; connection and TLS errors point at the host or certificate.",
            "A changed address leaves the provider calling the old one."
          ]
        },
        {
          "heading": "A safe first investigation without touching live payments",
          "body": [
            "Do not retest with a real card. Use the provider's own delivery log, which shows each delivery and the status the store returned, and compare payments with orders for one day by order number and amount only."
          ],
          "items": [
            "In the provider dashboard, open the delivery list and note the status code and time on recent entries.",
            "For the WooCommerce Stripe extension, check that both the Live and Test tabs show Configured.",
            "List payments that succeeded and find their orders; mark any still Pending payment or On hold.",
            "Ask what changed before it started: domain, https, host, security plugin, caching or a site copy.",
            "Never put keys or signing secrets in an email or screenshot."
          ]
        },
        {
          "heading": "What fixes it, and what does not fit",
          "body": [
            "Fixes are usually small and on the store side: make the webhook address answer directly without a redirect, let the provider through a security rule, or recreate the webhooks from the extension's settings. Stripe can resend events from its dashboard for up to 15 days, and a manual resend does not stop its automatic retries, so resending is a recovery step once the cause is fixed. If the payment itself fails at checkout, or the method is meant to wait for manual confirmation, this is a different problem. Refunds, disputes and reconciling money with the provider are yours to handle under your own account."
          ],
          "items": []
        },
        {
          "heading": "How the paid fix is accepted",
          "body": [
            "The fixed job for this problem is accepted on a staging copy reachable over HTTPS with the gateway in test mode. A successful test payment moves the order to the agreed status and reduces stock once, the provider's delivery log shows the event delivered with a success status, a declined test payment leaves no paid order, and a second delivery of the same event changes nothing. You or your host make any dashboard or firewall change; we never see live keys or signing secrets."
          ],
          "items": []
        }
      ],
      "incoming": [
        "example-woocommerce-test-order-matrix",
        "guide-woocommerce-subscription-renewals-scheduler",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/woocommerce-pending-payment-gateway-confirmation/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/woocommerce-pending-payment-gateway-confirmation/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fwoocommerce-pending-payment-gateway-confirmation%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fwoocommerce-pending-payment-gateway-confirmation%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-woocommerce-subscription-renewals-scheduler",
      "type": "guide",
      "title": "Why WooCommerce Subscriptions renewals run late: the scheduler behind every renewal",
      "description": "How a renewal is triggered by Action Scheduler and WP-Cron, why quiet sites and disabled cron leave renewals overdue, and how to test on a copy.",
      "slug": "woocommerce-subscription-renewals-scheduler",
      "url": "/guides/woocommerce-subscription-renewals-scheduler/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "WooCommerce Subscriptions documentation: The renewal process",
          "url": "https://woocommerce.com/document/subscriptions/renewal-process/",
          "checked": "2026-10-11",
          "claims": [
            "In its section on deactivating a payment gateway, the page says that when a subscription's scheduled renewal is due and a scheduled subscription payment is triggered (the woocommerce_scheduled_subscription_payment event in Action Scheduler), a renewal order is created with Pending payment status.",
            "The next renewal date normally counts from the last actual payment, not the scheduled date.",
            "Automatic renewals charge the original gateway; if a gateway plugin is deactivated entirely, its subscriptions switch to manual renewal.",
            "A manual renewal order is emailed to the customer if the store has enabled the Customer Renewal Invoice email.",
            "By default a failed payment leaves the subscription on hold, and the customer is emailed about the failure only if the Customer Renewal Invoice email is activated.",
            "A renewal can be triggered for a test subscription only with a manual-payment gateway or a gateway that supports changing the renewal date."
          ]
        },
        {
          "label": "Action Scheduler documentation",
          "url": "https://actionscheduler.org/",
          "checked": "2026-10-11",
          "claims": [
            "The runner hooks into an action fired by WP-Cron about once a minute, and on admin requests it also checks for pending actions and starts a queue through an async loopback request.",
            "A runner claims 25 actions at a time and keeps taking batches until it reaches 90 percent of available memory or 30 seconds, then makes a new loopback request if work remains.",
            "Claims older than five minutes are released, and an action running over five minutes is marked failed."
          ]
        },
        {
          "label": "WordPress Plugin Handbook: Cron",
          "url": "https://developer.wordpress.org/plugins/cron/",
          "checked": "2026-10-11",
          "claims": [
            "WP-Cron is not a background process: on each page request WordPress runs any jobs that are due, so it is only triggered on page load.",
            "Execution times are approximate, low-traffic sites are more likely to see delays, and overdue tasks stay in the queue and run on the next request."
          ]
        },
        {
          "label": "WordPress Plugin Handbook: Hooking WP-Cron into the system task scheduler",
          "url": "https://developer.wordpress.org/plugins/cron/hooking-wp-cron-into-the-system-task-scheduler/",
          "checked": "2026-10-11",
          "claims": [
            "WP-Cron does not run continuously, so time-critical tasks may run late.",
            "DISABLE_WP_CRON can be set in wp-config.php once a system scheduler makes a recurring web request to wp-cron.php."
          ]
        },
        {
          "label": "WooCommerce Subscriptions documentation: How Subscriptions handles staging sites",
          "url": "https://woocommerce.com/document/subscriptions/subscriptions-handles-staging-sites/",
          "checked": "2026-10-11",
          "claims": [
            "Subscriptions records the URL of the site where it was first activated; if the site URL then differs, it treats the site as a staging site and runs in staging mode.",
            "In staging mode automatic payments and subscription-related emails are disabled and all subscriptions use manual renewal, while scheduled renewals and other scheduled events still fire and create renewal orders.",
            "If a database is migrated and the same domain name is kept, the new site does not trigger staging mode."
          ]
        }
      ],
      "related": [
        "woo-subscription-renewals-not-processing",
        "platform-wordpress-woocommerce",
        "checkout-keep-test-order-passing-through-updates",
        "guide-woocommerce-pending-payment-gateway-confirmation",
        "platform-stripe"
      ],
      "sections": [
        {
          "heading": "A renewal is a scheduled task, not a charge waiting to happen",
          "body": [
            "WooCommerce Subscriptions does not watch the clock itself; each renewal is a scheduled event. When a renewal falls due, the plugin's documentation describes a scheduled subscription payment being triggered, the woocommerce_scheduled_subscription_payment event in Action Scheduler, and a renewal order being created. With automatic renewals the original payment gateway is then charged. With manual renewals the order starts as Pending payment, and the customer is emailed a Customer Renewal Invoice to pay if your store has that email enabled.",
            "That means a late renewal can be two different faults. Either the task did not run on time, which is a scheduling problem, or it ran and the payment failed, which is a gateway problem. They need different evidence, and this guide covers the first. A renewal order that exists but whose card payment failed is not a scheduling fault; by default, a failed payment leaves the subscription on hold, and the customer is emailed about it only if the Customer Renewal Invoice email is activated."
          ],
          "items": [
            "No renewal order at the due time: look at scheduling.",
            "Renewal order created, payment failed: look at the gateway log and failed-payment settings.",
            "The next renewal date counts from the last actual payment, so a late payment shifts later dates."
          ]
        },
        {
          "heading": "What starts Action Scheduler",
          "body": [
            "Action Scheduler is a queue library that WooCommerce and many extensions use for background work. Its documentation describes two triggers. The first is WP-Cron, which fires the runner about once a minute. The second is the admin: on admin requests it checks for pending actions at the end of the request and, if any are due, starts a queue through an asynchronous loopback request, meaning the site calls itself over the network.",
            "Once started, a runner claims 25 actions at a time and keeps going until it reaches 90 percent of available memory or 30 seconds, then asks for a new loopback request if work remains. Claims older than five minutes are released, and an action running longer than five minutes is marked failed. A large backlog, a slow host or a loopback request that the host blocks can therefore leave tasks waiting or failed with no message to a subscriber."
          ],
          "items": []
        },
        {
          "heading": "Why quiet sites and disabled cron leave renewals overdue",
          "body": [
            "WP-Cron is not a clock. WordPress documents that it runs only when someone loads a page, checks its queue and runs whatever is due. A job set for 2pm on a site nobody visits until 5pm runs at 5pm. Overdue jobs are not skipped; they run on the next request. For a subscription store that means renewals bunch up behind visitors, and a quiet night can push them hours late.",
            "Many hosts replace the page-load trigger with a real scheduled job. The WordPress handbook describes setting DISABLE_WP_CRON in the site configuration and making the host call the cron file on a schedule instead, for example every fifteen minutes. If the first half was done and the second half never was, nothing triggers the scheduler except admin visits, which matches the symptom of renewals that appear only when someone logs in."
          ],
          "items": [
            "Ask the host: is WordPress cron the default, or is there a server job calling it?",
            "If the constant is set, confirm a server job exists and runs.",
            "Check whether the site can request its own address; a firewall or password gate can block the loopback."
          ]
        },
        {
          "heading": "A safe first investigation on a copy",
          "body": [
            "Use a staging copy with live payments off, never the live subscriptions. Look at the list of scheduled tasks and filter to the subscription payment tasks.",
            "Check how your copy behaves before you test. WooCommerce Subscriptions records the address of the site where it was first activated, and if the copy has a different address it runs in staging mode: automatic payments and subscription emails are switched off and every subscription is treated as a manual renewal, but scheduled renewals still fire and create renewal orders. That is what you want for this test. A copy that keeps the live address, for example after a database migration on the same domain, does not trigger staging mode, so Subscriptions may treat it as the live site and could still try to charge subscribers; do not test on such a copy unless live payments are off at the gateway."
          ],
          "items": [
            "Pending tasks whose due time is hours or days in the past point at a trigger that is not running.",
            "Failed tasks with a timeout note point at memory, time or loopback limits.",
            "Check whether subscriptions fell back to manual renewal because a gateway plugin was deactivated; reactivating it should restore automatic renewals.",
            "Make a test subscription due now: Subscriptions can trigger a renewal for a test subscription only with a manual-payment gateway or a gateway that supports changing the renewal date.",
            "Record when the renewal order appears and when the next renewal is scheduled."
          ]
        },
        {
          "heading": "What fixes it, and what does not fit",
          "body": [
            "Fixes are in two places. On the store, make sure the gateway plugin is active, clear tasks that failed for a documented reason, and settle the configuration. On the server, make sure something triggers WordPress cron regularly, at an interval your host accepts. If an overdue backlog exists, reduce it deliberately before the scheduler is fixed on live, so hundreds of renewals do not fire at once. Declined cards, retry rules, price changes and refunds are outside a scheduling repair, and no staging test should ever renew or charge a live subscriber."
          ],
          "items": []
        },
        {
          "heading": "How the paid fix is accepted",
          "body": [
            "The fixed job for this problem is accepted on a staging copy with live payments off. A test subscription made due now gets its renewal order created inside the agreed window, its next renewal is scheduled, no subscription payment task is pending past its due time by more than the agreed margin, and the scheduler setting we specify matches what your host confirms is running. We never renew or charge your live subscribers; you review the overdue list we produce and act on it under your own account."
          ],
          "items": []
        }
      ],
      "incoming": [
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/woocommerce-subscription-renewals-scheduler/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/woocommerce-subscription-renewals-scheduler/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fwoocommerce-subscription-renewals-scheduler%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fwoocommerce-subscription-renewals-scheduler%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-woocommerce-update-test-order-script",
      "type": "guide",
      "title": "What a WooCommerce test-order script should cover before an update reaches your live store",
      "description": "A practical set of checkout cases to run on a staging copy before updating, with what to record for each and what a pass does and does not prove.",
      "slug": "woocommerce-update-test-order-script",
      "url": "/guides/woocommerce-update-test-order-script/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "WooCommerce documentation: How to test for conflicts",
          "url": "https://woocommerce.com/document/how-to-test-for-conflicts/",
          "checked": "2026-10-11",
          "claims": [
            "A staging clone or a backup protects the live store while testing for conflicts.",
            "Testing steps include switching to a default theme, deactivating plugins other than WooCommerce and the extensions involved, retesting and reactivating plugins one at a time.",
            "Must-use plugins and drop-ins cannot be switched off directly but may cause a conflict, and browser caching should be disabled while testing."
          ]
        },
        {
          "label": "WooCommerce documentation: Order statuses",
          "url": "https://woocommerce.com/document/managing-orders/order-statuses/",
          "checked": "2026-10-11",
          "claims": [
            "Processing means paid with stock deducted, Failed returns stock to inventory, and On hold is typical for delayed-notification methods.",
            "A scheduled job deletes inactive Draft orders created by block-based checkout."
          ]
        },
        {
          "label": "WooCommerce documentation: Setting up shipping zones",
          "url": "https://woocommerce.com/document/setting-up-shipping-zones/",
          "checked": "2026-10-11",
          "claims": [
            "Each customer matches only one shipping zone, first match from the top of the list."
          ]
        },
        {
          "label": "WooCommerce documentation: Variable products",
          "url": "https://woocommerce.com/document/variable-product/",
          "checked": "2026-10-11",
          "claims": [
            "Variations without prices do not show in the store."
          ]
        }
      ],
      "related": [
        "checkout-keep-test-order-passing-through-updates",
        "store-recovery-woocommerce-after-failed-update",
        "woocommerce-checkout-after-update",
        "guide-woocommerce-checkout-conflicts",
        "example-woocommerce-test-order-matrix",
        "platform-wordpress-woocommerce"
      ],
      "sections": [
        {
          "heading": "A script is a list of journeys with an expected result for each",
          "body": [
            "After a bad update, owners usually test by placing one order and seeing it work. One order proves one path. A test-order script is a short, fixed list of journeys, each with the result you expect, that you run in the same way before and after an update. Its value is comparison: the same eight cases pass on Tuesday and fail on Wednesday, so the update is the suspect. Keep the list small enough to run in half an hour, and write the expected result before you run it.",
            "Run it on a staging copy, as the WooCommerce conflict-testing guidance advises, so a failed test cannot cost live sales. Take a backup first, and disable browser caching while testing so a stale page cannot hide the real result."
          ],
          "items": [
            "Same cases, same order, same test data every time.",
            "Expected result written first.",
            "Evidence recorded: order number, status, total, screenshot."
          ]
        },
        {
          "heading": "The cases worth including",
          "body": [
            "Pick journeys that carry money or customers. Each should name the product, the shopper type, the address and the payment method, so a different person can repeat it."
          ],
          "items": [
            "A guest buying a simple product with a test card: the order reaches Processing with the right total and stock drops once.",
            "A signed-in customer buying a variable product: the exact size and colour chosen is the variation in the cart.",
            "One address for each shipping zone you serve, and one you do not: methods and costs match your table.",
            "A coupon you actually use: the discount line and total are right.",
            "A declined test card: no paid order remains and stock is returned, since Failed orders return stock.",
            "The order confirmation email, with customer email routed to a test address.",
            "The payment provider's delivery log for the test payment: the confirmation shows delivered with a success status.",
            "If you sell subscriptions: a test renewal, on a gateway that supports changing the renewal date."
          ]
        },
        {
          "heading": "Preparing the copy so a test cannot hurt anyone",
          "body": [
            "A staging copy often inherits live settings. Before running anything, switch payments to test mode with test keys you enter yourself, turn off customer emails or route them to a test inbox, and confirm no live fulfilment or accounting connection will fire. Check that stock changes on the copy cannot reach a live feed. If the copy is not reachable from the internet, provider confirmations cannot arrive, so a test of the confirmation path needs a copy on a public address."
          ],
          "items": [
            "Test-mode keys entered by you; never share live keys.",
            "Customer emails off or redirected.",
            "No live feeds connected to the copy."
          ]
        },
        {
          "heading": "Reading the result: what a pass proves, and what it does not",
          "body": [
            "A pass means the agreed cases worked on the copy with the updates you applied there. It does not prove live checkout, because live differs in caching, keys, host rules and real cards. After applying updates on live, place one real order of your own and check it. A fail is only useful if you can isolate it, so when a case fails, follow the conflict-testing steps on the copy: switch to a default theme, deactivate plugins other than WooCommerce and the ones involved, retest, then reactivate one at a time. Must-use plugins and drop-ins that a host installs cannot be switched off directly and may still be the cause; ask the host."
          ],
          "items": []
        },
        {
          "heading": "What a script cannot replace",
          "body": [
            "It does not monitor your store between updates, back it up, or detect a compromise. If you find unknown admin users or an altered payment form, stop testing and treat it as a security incident first. Pricing, design and performance changes are separate work."
          ],
          "items": []
        },
        {
          "heading": "How the paid services use it",
          "body": [
            "The standing service built on this guide applies your pending updates to a copy each month, runs your agreed script before and after, and sends an apply or hold recommendation with evidence; you decide and you update live. The recovery project uses the same script as its acceptance checklist. In both, a pass is reported as a pass on the agreed cases only."
          ],
          "items": []
        }
      ],
      "incoming": [
        "example-woocommerce-test-order-matrix",
        "guide-woocommerce-variation-attributes-and-any",
        "guide-woocommerce-shipping-zone-order-and-postcodes",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/woocommerce-update-test-order-script/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/woocommerce-update-test-order-script/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fwoocommerce-update-test-order-script%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fwoocommerce-update-test-order-script%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-magento-indexers-schedule-cron-triggers",
      "type": "guide",
      "title": "Why Magento edits do not show on the storefront: indexer modes, cron and missing triggers",
      "description": "How Magento 2 and Adobe Commerce indexers keep the storefront current, what stops them, and the read-only checks a host can run before any change.",
      "slug": "magento-indexers-schedule-cron-triggers",
      "url": "/guides/magento-indexers-schedule-cron-triggers/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Adobe Commerce documentation: Manage the indexers",
          "url": "https://experienceleague.adobe.com/en/docs/commerce-operations/configuration-guide/cli/manage-indexers",
          "checked": "2026-10-11",
          "claims": [
            "Update on Save refreshes the index when a change is made in the Admin, while Update by Schedule refreshes it on the schedule set by the cron job.",
            "Database triggers are added in schedule mode and removed in realtime mode, and if they go missing, switching to realtime and back recreates them.",
            "The indexer reindex command runs once, so a cron job is required to keep indexers current in schedule mode.",
            "Invalid flags data as out of date so the next cron run reindexes it unless it is suspended, and suspended pauses automatic cron updates.",
            "Before switching modes, put the site in maintenance mode and disable cron jobs to avoid database locks.",
            "Before 2.4.8 the customer grid indexer supported only Update on Save; from 2.4.8 it supports both modes.",
            "Setting an indexer to valid when unindexed data has built up can degrade performance."
          ]
        },
        {
          "label": "Adobe Commerce knowledge base: Changes in the database are not reflected on the storefront",
          "url": "https://experienceleague.adobe.com/docs/commerce-knowledge-base/kb/troubleshooting/database/changes-in-the-database-are-not-reflected-on-the-storefront.html",
          "checked": "2026-10-11",
          "claims": [
            "The article applies to Adobe Commerce 2.2.x and 2.3.x and ties stale storefront data to indexers configured to update by schedule.",
            "Causes named are oversized change-log tables, which grow when the indexer_update_all_views cron job repeatedly fails to finish, and missing MySQL triggers.",
            "Failed runs can be found by querying the cron schedule table for that job code with a status other than success or pending.",
            "The article asks for a backup first and avoiding heavy traffic."
          ]
        }
      ],
      "related": [
        "magento-catalogue-changes-not-showing-indexers-cron",
        "platform-magento",
        "guide-store-catalogue-move-option-variant-limits",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "sections": [
        {
          "heading": "The storefront reads an index, not the admin",
          "body": [
            "When a Magento administrator saves a price, a stock level or a new product, the change goes to the database tables the admin uses. The storefront does not read those tables directly. It reads index tables that Magento builds from them, and the indexers are what keep the two in step. If the indexer has not run, the admin shows the new price and the product page still shows the old one, and both are doing what they were designed to do.",
            "Adobe's documentation names two modes. Update on Save refreshes an index when a change is made in the admin. Update by Schedule refreshes it on the schedule set by the cron job. The price of schedule mode is a dependency: a recurring job must keep running."
          ],
          "items": [
            "Update on Save: changes apply when saved.",
            "Update by Schedule: a background job applies them.",
            "Customer grid supported only Update on Save before 2.4.8; from 2.4.8 it supports both."
          ]
        },
        {
          "heading": "What schedule mode needs in place",
          "body": [
            "In schedule mode, Magento adds database triggers that record each change into a change-log table, and the cron job later reads that log and updates the index. The reindex command is a one-time run, so it can fix the symptom once but cannot keep the storefront current; Adobe says a cron job is needed for that. If the job does not run, edits queue up unseen. If it runs and fails, the change-log tables grow. Adobe's knowledge-base article ties exactly this pattern to the job named indexer_update_all_views repeatedly failing to finish, and to triggers that are missing. That article is written for Adobe Commerce 2.2.x and 2.3.x, so check how it carries to your version."
          ],
          "items": [
            "Cron not running: no recent runs of the indexing job.",
            "Cron failing: runs recorded with a status other than success or pending.",
            "Triggers missing: edits add no rows to the change-log table.",
            "Indexer suspended: automatic cron updates are paused until it is released."
          ]
        },
        {
          "heading": "Read-only checks a host can run first",
          "body": [
            "Nothing here changes data. Ask your host or developer to run these on a staging copy and send the redacted output."
          ],
          "items": [
            "The indexer status command: which indexers exist, their mode and whether any is invalid or suspended, with any backlog count.",
            "The indexer info command: the full list of indexers.",
            "A query on the scheduled jobs table for the indexing job and a status that is not success or pending.",
            "Whether any scheduled job ran in the last hour.",
            "Magento or Adobe Commerce version, since behaviour differs between 2.4 releases."
          ]
        },
        {
          "heading": "What fixes it, and the order to do it in",
          "body": [
            "Fixes follow the cause. If the job is not running, restore the cron configuration. If it keeps failing, find why it fails and let it complete, then the change-log backlog clears. If triggers are missing, Adobe says to switch the indexer to realtime and back to schedule so they are recreated, and to put the site in maintenance mode and disable cron jobs first to avoid database locks. Setting an indexer to valid without checking that the data is indexed can leave stale data in place and degrade performance.",
            "A full reindex of a large catalogue can take a long time, so plan it for a quiet period."
          ],
          "items": [
            "Back up the database first, and avoid peak traffic.",
            "Run commands as the file system owner.",
            "Never mark an indexer valid just to clear a warning."
          ]
        },
        {
          "heading": "What does not fit",
          "body": [
            "This guide covers staleness caused by indexers and cron. It does not cover a cache or content delivery layer serving old pages, search service faults, extensions that write data incorrectly, or data that is wrong in the admin itself. If a manual reindex makes no difference, look elsewhere. Performance tuning and upgrades are separate work."
          ],
          "items": []
        },
        {
          "heading": "How the paid fix is accepted",
          "body": [
            "The fixed job for this problem is accepted on a staging copy. Every indexer is in the agreed mode and none is invalid or suspended, the scheduled job that applies index changes shows recent successful runs with none stuck pending, a test product price edit appears on its storefront page within the agreed time, and a test stock change appears in a category listing. Your host applies the change on live, in a maintenance window; we do not touch the live database."
          ],
          "items": []
        }
      ],
      "platforms": [
        "magento"
      ],
      "incoming": [
        "platform-magento",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/magento-indexers-schedule-cron-triggers/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/magento-indexers-schedule-cron-triggers/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fmagento-indexers-schedule-cron-triggers%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fmagento-indexers-schedule-cron-triggers%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-bigcommerce-webhook-retries-deactivation",
      "type": "guide",
      "title": "BigCommerce order webhooks: how they fail, retry and get deactivated",
      "description": "The answer rules, the retry schedule and the deactivation conditions behind BigCommerce webhooks, and how to find the orders a deactivated one missed.",
      "slug": "bigcommerce-webhook-retries-deactivation",
      "url": "/guides/bigcommerce-webhook-retries-deactivation/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "BigCommerce developer documentation: Webhooks overview",
          "url": "https://docs.bigcommerce.com/developer/docs/integrations/webhooks/overview.md",
          "checked": "2026-10-11",
          "claims": [
            "The destination must return an HTTP 200 response, and no response or a non-200 response counts as not received.",
            "Destinations must use port 443, and the page advises replying immediately before doing other work.",
            "Success is measured over a two-minute window; if it falls below 90 percent, the client is blocklisted for three minutes, and no ratio is calculated until 100 requests are sent.",
            "Held-back events are retried 11 times, at intervals from 60 seconds up to 86,400 seconds, over a cumulative 48 hours.",
            "After the last retry the webhook is deactivated and an email goes to the subscribing app's registered address; it is reactivated by setting is_active back to true.",
            "A subscription is also deactivated after 90 days of inactivity, and webhooks are deleted when the app is uninstalled or the API account is deleted.",
            "Duplicates may occasionally occur and can be handled by keeping a temporary list of processed hash values.",
            "Payloads are light and carry just an ID, so full details are fetched through the API.",
            "A maximum of 10 webhooks per store, client and scope applies, and a new webhook can take up to a minute to start working."
          ]
        }
      ],
      "related": [
        "bigcommerce-order-webhook-deactivated-orders-not-syncing",
        "platform-bigcommerce",
        "store-keep-order-inventory-sync-healthy",
        "guide-store-reconciling-orders-and-stock-between-systems",
        "guide-stripe-webhook-delivery"
      ],
      "sections": [
        {
          "heading": "What a BigCommerce webhook is promising",
          "body": [
            "A BigCommerce webhook is a short notification that something happened, sent to an address you registered. For orders, the documentation names scopes such as an order being updated or its status being updated. The notification is deliberately light: it carries an identifier, not the order, so the receiver is expected to fetch the details from the API. That design puts the load on the receiver, and it is the receiver's answers that decide whether BigCommerce keeps sending."
          ],
          "items": [
            "The notification says that something changed, not what the order contains.",
            "A receiver that fails to fetch the order after acknowledging loses it silently."
          ]
        },
        {
          "heading": "What counts as a good answer",
          "body": [
            "BigCommerce requires an HTTP 200 response. No response, or one outside the 200 range, is treated as not received. The destination must use port 443; custom ports are not supported. The documentation gives no response time limit, but advises answering immediately, before any other work, to avoid timeouts. Headers and bodies in the response are unnecessary and discouraged. The practical rule for the receiver is therefore: write down the notification, answer 200 straight away, and do the processing afterwards."
          ],
          "items": [
            "A redirect, a 4xx or 5xx status, and a timeout are all failures from BigCommerce's point of view.",
            "A receiver that does slow work before answering invites timeouts."
          ]
        },
        {
          "heading": "The retry schedule and how a webhook ends up deactivated",
          "body": [
            "BigCommerce measures success over a sliding two-minute window. When the success rate falls below 90 percent, and after at least 100 requests in the window, that client is blocklisted for three minutes; this is judged per domain, not per webhook. Notifications that were held back are retried at increasing intervals: 11 retries from 60 seconds up to 86,400 seconds, over a cumulative 48 hours. After the last retry the webhook is deactivated and an email is sent to the registered address of the subscribing app.",
            "That email matters, because the person who receives it may not be the store owner. A webhook is also deactivated after 90 days of inactivity, and webhooks are deleted outright when the app is uninstalled or the API account is deleted. Reactivation after a deactivation is an update that sets the active flag back to true; deletion needs a new subscription."
          ],
          "items": [
            "48 hours of retries, then deactivation.",
            "Orders placed after deactivation are never announced.",
            "The documentation describes no replay of notifications missed while a webhook was inactive."
          ]
        },
        {
          "heading": "Duplicates, limits and timing",
          "body": [
            "Duplicates can occasionally occur, from network glitches or retries, so a receiver should keep a temporary list of the hash values it has processed and ignore repeats. A store can have at most 10 webhooks per store, client and scope, and only one per scope and destination. A new webhook can take up to a minute to start working. Do not assume notifications arrive in order; the documentation makes no promise about ordering."
          ],
          "items": []
        },
        {
          "heading": "A safe first investigation",
          "body": [
            "Start with evidence you own. You need the time the connected system last received an order, the list of order IDs BigCommerce holds for the days since, and the list the connected system holds."
          ],
          "items": [
            "Find the first missing order: its time marks the start of the gap, and 48 hours before it is when retries began.",
            "Ask whoever created the API account whether an email about a deactivated webhook arrived.",
            "List the store's webhooks and read the active flag and destination for each.",
            "Check the receiver: does it answer 200 immediately, over the standard port, with no redirect?",
            "Never share API credentials in an email; the person who owns the account runs the list and re-activation."
          ]
        },
        {
          "heading": "What fixes it, and what does not fit",
          "body": [
            "Fix the receiver first, then reactivate. If the receiver still fails after reactivation, the webhook will deactivate again after another 48 hours. Then close the gap: The documentation describes no replay of notifications missed while a webhook was inactive, so compare order ID lists and load the missing orders into the connected system. If the webhook was deleted because an app was uninstalled, a new subscription is needed, which is a larger rebuild. A third-party receiver you cannot change is its vendor's to fix."
          ],
          "items": []
        },
        {
          "heading": "How the paid fix is accepted",
          "body": [
            "The fixed job for this problem is accepted on a copy of your receiver with synthetic notifications. It answers 200 before processing and records each notification, a notification sent twice produces one record, a burst of notifications is all acknowledged with no error status, and a gap list names every order in the store that is absent from the connected system. You run the re-activation under your own account; we never receive your credentials."
          ],
          "items": []
        }
      ],
      "platforms": [
        "bigcommerce"
      ],
      "incoming": [
        "guide-store-reconciling-orders-and-stock-between-systems",
        "platform-bigcommerce",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/bigcommerce-webhook-retries-deactivation/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/bigcommerce-webhook-retries-deactivation/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fbigcommerce-webhook-retries-deactivation%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fbigcommerce-webhook-retries-deactivation%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "platform-bigcommerce",
      "type": "platform",
      "title": "BigCommerce order notifications and shipping setup: what the store promises and what your systems must do",
      "description": "Understand how BigCommerce tells other systems about orders, how its shipping zones and carrier connections are organised, and where a quiet failure hides.",
      "slug": "bigcommerce",
      "url": "/platforms/bigcommerce/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "BigCommerce developer documentation: Webhooks overview",
          "url": "https://docs.bigcommerce.com/developer/docs/integrations/webhooks/overview.md",
          "checked": "2026-10-11",
          "claims": [
            "Webhooks notify a destination with an ID-only payload, and the destination must return HTTP 200.",
            "Retries run 11 times over a cumulative 48 hours, after which the webhook is deactivated and an email goes to the subscribing app's registered address.",
            "Webhooks are deleted when the app is uninstalled or the API account is deleted."
          ]
        },
        {
          "label": "BigCommerce developer documentation: Shipping overview",
          "url": "https://docs.bigcommerce.com/developer/docs/admin/store-configuration/shipping/overview.md",
          "checked": "2026-10-11",
          "claims": [
            "Shipping zones define the regions a merchant delivers to and which methods are offered in each, and can be set up in the control panel or through the API.",
            "Methods are attached to zones, and BigCommerce has built-in integrations with live-rate carriers including UPS, FedEx and USPS, linked through a carrier connection.",
            "A checkout always has one consignment assigned to it, and shipments are created from finalised orders."
          ]
        }
      ],
      "related": [
        "bigcommerce-order-webhook-deactivated-orders-not-syncing",
        "guide-bigcommerce-webhook-retries-deactivation",
        "store-keep-order-inventory-sync-healthy",
        "guide-store-reconciling-orders-and-stock-between-systems",
        "buyer-merchant-ops-store-without-developer",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "sections": [
        {
          "heading": "Orders reach other systems through short notifications",
          "body": [
            "A BigCommerce store does not push full orders to the systems that depend on it. It sends a short notification, an identifier and a scope such as an order being updated, to an address registered with an API account, and the receiving system fetches the order. The receiver must answer HTTP 200. If it does not, BigCommerce retries on a schedule of 11 attempts over 48 hours and then deactivates the webhook, emailing the subscribing app's registered address. After that, new orders are not announced and the connected system shows no error, because nothing arrives to fail."
          ],
          "items": [
            "The notification carries an ID, so the receiver has to fetch the order.",
            "Deactivation after retries run out is silent from the shop owner's side.",
            "The email goes to the app's registered address, which may not be the owner's."
          ]
        },
        {
          "heading": "Shipping is organised as zones, methods and carrier connections",
          "body": [
            "BigCommerce's shipping model has three parts. Zones define the regions you deliver to. Methods are attached to zones and decide what a shopper can choose there; the documentation's example offers free shipping, weight-based rates and a live-rate carrier in one zone. Carrier connections link your account with live-rate carriers such as UPS, FedEx and USPS. A checkout always has one consignment, which assigns line items to shipping addresses, and shipments are created only from finalised orders. A shipping problem therefore starts with one question: which zone and which method was the shopper offered."
          ],
          "items": [
            "Zone: where you deliver.",
            "Method: what is offered in that zone.",
            "Carrier connection: how live rates are fetched, where used."
          ]
        },
        {
          "heading": "What a connected system needs to do",
          "body": [
            "A receiver should acknowledge first and process afterwards, record each notification, ignore repeats, and fetch the current order rather than trusting the notification's timing. BigCommerce says duplicates may occur, and the usual protection is a temporary list of processed hash values. Whoever owns the integration should also know where the deactivation email goes, and should compare order counts between the store and the connected system on a schedule, because the notification path alone cannot prove nothing was missed."
          ],
          "items": []
        },
        {
          "heading": "What a paid outcome here covers, and what it does not",
          "body": [
            "The fixed job for a deactivated order webhook corrects a receiver you control, tests it with synthetic notifications, lists the orders in the missed window and gives you the steps to reactivate the webhooks under your own account. The standing sync service runs a weekly comparison and explains up to two separate causes of difference a month; the correction itself is the fixed job. Neither changes your live store or holds your credentials. Third-party receivers you cannot change, and a webhook deleted because an app was uninstalled, are outside the fixed job, and a fixed job for carrier quote faults is not offered at this time."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-bigcommerce-webhook-retries-deactivation",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/platforms/bigcommerce/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/platforms/bigcommerce/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fplatforms%2Fbigcommerce%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fplatforms%2Fbigcommerce%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "platform-magento",
      "type": "platform",
      "title": "Magento and Adobe Commerce: indexers, cron and product exports as operational risks",
      "description": "Understand why Magento storefronts can lag behind the admin, what the scheduled jobs must do, and what a catalogue export contains when you move away.",
      "slug": "magento",
      "url": "/platforms/magento/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Adobe Commerce documentation: Manage the indexers",
          "url": "https://experienceleague.adobe.com/en/docs/commerce-operations/configuration-guide/cli/manage-indexers",
          "checked": "2026-10-11",
          "claims": [
            "Update by Schedule refreshes the index on the cron schedule, and the reindex command runs once, so a recurring cron job is needed in schedule mode.",
            "Indexers can be invalid or suspended, and missing database triggers are recreated by switching the mode to realtime and back.",
            "Before switching modes the site should be in maintenance mode with cron jobs disabled to avoid database locks."
          ]
        },
        {
          "label": "Adobe Commerce knowledge base: Changes in the database are not reflected on the storefront",
          "url": "https://experienceleague.adobe.com/docs/commerce-knowledge-base/kb/troubleshooting/database/changes-in-the-database-are-not-reflected-on-the-storefront.html",
          "checked": "2026-10-11",
          "claims": [
            "For Adobe Commerce 2.2.x and 2.3.x, stale storefront data under schedule mode is tied to oversized change-log tables, which grow when the indexer_update_all_views job repeatedly fails to finish, or to missing triggers."
          ]
        },
        {
          "label": "Adobe Commerce documentation: Export data",
          "url": "https://experienceleague.adobe.com/en/docs/commerce-admin/systems/data-transfer/data-export",
          "checked": "2026-10-11",
          "claims": [
            "Products are exported from System, Data Transfer, Export as CSV, running in the background through a queue that needs cron."
          ]
        },
        {
          "label": "Adobe Commerce documentation: Import configurable products",
          "url": "https://experienceleague.adobe.com/en/docs/commerce-admin/systems/data-transfer/examples/data-transfer-configurable-products",
          "checked": "2026-10-11",
          "claims": [
            "In a product export, configurable products appear as one row plus a row for each simple-product variation, linked by a configurable variations column."
          ]
        }
      ],
      "related": [
        "magento-catalogue-changes-not-showing-indexers-cron",
        "guide-magento-indexers-schedule-cron-triggers",
        "store-catalogue-mapping-to-shopify-csv",
        "guide-store-catalogue-move-option-variant-limits",
        "buyer-store-owner-moving-platforms",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "sections": [
        {
          "heading": "The storefront shows an index, so it can disagree with the admin",
          "body": [
            "Magento keeps what the admin edits separate from what shoppers see. Shoppers read index tables, and indexers rebuild them from the admin data. In Update by Schedule mode the rebuild is done by a recurring cron job. If that job does not run, or keeps failing, a price change saved in the admin does not appear on the product page, although the admin itself looks right. Adobe's documentation states that the one-time reindex command cannot keep indexers current and that a cron job is needed."
          ],
          "items": [
            "Admin right and storefront stale is the classic sign.",
            "A manual reindex that helps only for a while points at the recurring job.",
            "Behaviour differs between 2.4 releases, so the version matters."
          ]
        },
        {
          "heading": "What fails quietly",
          "body": [
            "Adobe's knowledge base article for Adobe Commerce 2.2.x and 2.3.x names two causes under schedule mode: change-log tables that grow too large because the indexing job repeatedly fails to finish, and database triggers that have gone missing. Indexers can also be flagged invalid, or suspended, which pauses automatic cron updates. None of these shows a message to a shopper or to an administrator saving a product."
          ],
          "items": [
            "Look at indexer status, not just the admin.",
            "Look at the scheduled job history for failures.",
            "Do not mark an indexer valid just to clear a warning."
          ]
        },
        {
          "heading": "Care before changing modes on a live store",
          "body": [
            "Switching an indexer's mode to recreate triggers is a documented fix, but Adobe says to put the site in maintenance mode and disable cron jobs first, to avoid database locks. A full reindex of a large catalogue can take a long time. For those reasons the work is done and timed on a staging copy first, and your host applies it on live in a maintenance window."
          ],
          "items": []
        },
        {
          "heading": "The catalogue export if you are leaving",
          "body": [
            "Magento exports products as CSV from the admin's data transfer area, in the background, through a queue that needs cron to be running. A configurable product is one row plus a row for each of its simple products, linked through a column of SKU-and-attribute entries. A move to another platform starts by reshaping those rows, which the catalogue-move guide and the Shopify file job describe."
          ],
          "items": []
        },
        {
          "heading": "What a paid outcome covers here",
          "body": [
            "The fixed job for a storefront that does not show changes works on a staging copy: it checks indexer status, the indexing job history and the triggers, corrects what is wrong, and proves a test product edit appears within an agreed time. Your host applies it on live. Cache or content delivery layers, extension bugs, performance tuning and upgrades are outside it."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-store-catalogue-move-option-variant-limits",
        "guide-magento-indexers-schedule-cron-triggers",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/platforms/magento/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/platforms/magento/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fplatforms%2Fmagento%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fplatforms%2Fmagento%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "buyer-merchant-ops-store-without-developer",
      "type": "buyer",
      "title": "For a store operator without a developer: describe the fault so it can be fixed on a copy",
      "description": "How to say where an order, payment, shipping or stock fault stops, what to send first, and how to choose between a single fix, a standing check and a recovery project.",
      "slug": "merchant-ops-store-without-developer",
      "url": "/buyers/merchant-ops-store-without-developer/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "WooCommerce documentation: How to test for conflicts",
          "url": "https://woocommerce.com/document/how-to-test-for-conflicts/",
          "checked": "2026-10-11",
          "claims": [
            "A backup or staging clone protects the live store while testing for faults."
          ]
        },
        {
          "label": "Shopify Help Center: Abandoned checkouts",
          "url": "https://help.shopify.com/en/manual/orders/abandoned-checkouts",
          "checked": "2026-10-11",
          "claims": [
            "Shopify lists the cases where no abandoned checkout email is sent, which should be checked before suspecting settings."
          ]
        },
        {
          "label": "WooCommerce documentation: Order statuses",
          "url": "https://woocommerce.com/document/managing-orders/order-statuses/",
          "checked": "2026-10-11",
          "claims": [
            "Order statuses describe what the store knows about payment: Pending payment means no payment has arrived."
          ]
        }
      ],
      "related": [
        "woo-orders-stuck-pending-after-payment",
        "woo-no-shipping-options-for-destination",
        "shopify-discount-code-not-applying-as-intended",
        "store-keep-order-inventory-sync-healthy",
        "checkout-keep-test-order-passing-through-updates",
        "collection-store-checkout-order-flow-diagnosis",
        "buyer-ecommerce-owner-checkout"
      ],
      "sections": [
        {
          "heading": "Tell us where the order or the money stops",
          "body": [
            "A store has a chain: the shopper finds a product, chooses an option, gets a shipping method, applies a discount, pays, the payment is confirmed, an order appears, an email goes out, and another system hears about it. A fault is one link in that chain. Saying where it stops is the most useful thing you can send: no shipping for one country, a code refused, a payment taken but the order unpaid, renewals late, an order that never reached the warehouse system. Those are different faults with different fixes."
          ],
          "items": [
            "Name the platform and the link that breaks.",
            "Give two or three redacted examples with order numbers, not customer details.",
            "Say what changed just before it began."
          ]
        },
        {
          "heading": "Keep a copy, a test route and a baseline",
          "body": [
            "Nothing should be tried on live orders. A copy of the store, payments in test mode, customer email turned off, and a short list of the journeys that must work are the three things that make a fix safe and checkable. If you do not have a copy, your host or platform support can usually say how to make one; if the platform has a development store, that is a safe place to prove a repair."
          ],
          "items": [
            "Never send logins, payment keys or customer records in a first message.",
            "Write the expected result for each journey before anything is tested."
          ]
        },
        {
          "heading": "Choosing between a single fix, a standing check and a recovery",
          "body": [
            "If one link is broken and everything else works, a single bounded fix is the right size. If you keep updating plugins or running a sync and are afraid of the next break, a standing check either tests your checkout journeys on a copy before your monthly update window or compares your orders and stock every week and explains up to two separate causes of any gap a month. Repairs stay separate jobs. If several links broke after one event and fixing one reveals another, a recovery project works through them against a checklist until the whole journey passes. Prices on our pages are published test prices that nobody has yet responded to, and payment follows agreed checks and your sign-off."
          ],
          "items": []
        },
        {
          "heading": "What to expect from the first reply",
          "body": [
            "You should get a plain statement of whether the problem fits a fixed job, what is needed before any access, what a staging test will show and which parts only you or your host can change. We say when a cause sits with a payment provider, a host or a vendor, because no fixed job can fix those. Nothing starts before scope, price and terms are agreed in writing."
          ],
          "items": []
        }
      ],
      "platforms": [
        "bigcommerce"
      ],
      "incoming": [
        "platform-bigcommerce",
        "collection-store-checkout-order-flow-diagnosis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/buyers/merchant-ops-store-without-developer/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/buyers/merchant-ops-store-without-developer/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fbuyers%2Fmerchant-ops-store-without-developer%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fbuyers%2Fmerchant-ops-store-without-developer%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "buyer-store-owner-moving-platforms",
      "type": "buyer",
      "title": "For a store owner moving platforms: move the catalogue without trusting a bare import",
      "description": "What to decide and prepare before moving a product catalogue to Shopify, how to prove it on a test store, and what stays your job.",
      "slug": "store-owner-moving-platforms",
      "url": "/buyers/store-owner-moving-platforms/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Shopify Help Center: Migrating to Shopify",
          "url": "https://help.shopify.com/en/manual/migrating-to-shopify",
          "checked": "2026-10-11",
          "claims": [
            "Shopify describes CSV and migration-app routes, an import order of products, customers then orders, and redirects set before moving the domain."
          ]
        },
        {
          "label": "Shopify Help Center: Importing products with a CSV file",
          "url": "https://help.shopify.com/en/manual/products/import-export/import-products",
          "checked": "2026-10-11",
          "claims": [
            "Shopify recommends exporting first and testing large imports on a development store."
          ]
        },
        {
          "label": "WooCommerce documentation: Product CSV Importer and Exporter",
          "url": "https://woocommerce.com/document/product-csv-importer-exporter/",
          "checked": "2026-10-11",
          "claims": [
            "WooCommerce exports variable products as a parent row and variation rows."
          ]
        }
      ],
      "related": [
        "store-catalogue-mapping-to-shopify-csv",
        "shopify-csv-import-merged-or-overwrote-products",
        "guide-store-catalogue-move-option-variant-limits",
        "guide-store-redirects-and-launch-checks-after-replatform",
        "collection-store-catalogue-and-stock-integrity",
        "platform-shopify"
      ],
      "sections": [
        {
          "heading": "Decide the scope before the file",
          "body": [
            "A catalogue move is easy to describe and easy to underestimate. Decide what is moving: products and variants, or also customers, historical orders, reviews and pages. Products are the part a file can carry well; Shopify describes CSV and migration-app routes, and says customers and historical orders move by other routes. Write down which of the source platform's concepts must survive, such as options, categories and custom fields, so the mapping has rules to follow."
          ],
          "items": [
            "Count your products and variants.",
            "List products with more than three options; Shopify allows three.",
            "Decide what you are leaving behind on purpose."
          ]
        },
        {
          "heading": "Prove the import on a test store",
          "body": [
            "Shopify recommends exporting first and testing large imports on a development store. For a catalogue move that means building the files, importing on the test store, exporting again and comparing counts and a sample with the source before anything is imported to the real store. Image addresses must still be reachable while Shopify downloads them, so keep the old store online until every import has run."
          ],
          "items": [
            "Keep the old store online until imports and checks are finished.",
            "Export the new store's products before each live import."
          ]
        },
        {
          "heading": "Plan old addresses and launch checks",
          "body": [
            "Old product addresses need redirects set before the domain moves, and the most visited ones should be tested after launch. Place test orders for successful and failed payments before opening the store. No file can promise a search ranking result, and we do not promise one."
          ],
          "items": []
        },
        {
          "heading": "What stays your job",
          "body": [
            "You run the live import, the redirect import and the domain change under your own account, and you decide how to merge or split products that need more than three options. We send files, steps and comparisons, and we never hold your store logins."
          ],
          "items": []
        }
      ],
      "platforms": [
        "magento"
      ],
      "incoming": [
        "guide-store-redirects-and-launch-checks-after-replatform",
        "platform-magento",
        "collection-store-catalogue-and-stock-integrity"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/buyers/store-owner-moving-platforms/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/buyers/store-owner-moving-platforms/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fbuyers%2Fstore-owner-moving-platforms%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fbuyers%2Fstore-owner-moving-platforms%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "collection-store-checkout-order-flow-diagnosis",
      "type": "category",
      "title": "Store checkout and order faults: work along the buying journey to find the first broken link",
      "description": "A diagnosis order for an online store that loses orders or money: product choice, shipping, discount, payment confirmation, renewals, emails and downstream sync, with the paid route for each.",
      "url": "/collections/store-checkout-order-flow-diagnosis/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "shopify",
        "wordpress-woocommerce",
        "bigcommerce"
      ],
      "buyer_role": "Owner or operator of an online store without a developer, triaging an order-flow fault before asking for a repair",
      "purchase_trigger": "Sales dropped, customers report they cannot pay or were not served, or orders are missing downstream, and the cause is not obvious",
      "problem": "The operator needs to find which single link in the buying journey is the first to fail, instead of collecting unrelated fixes or testing on live orders.",
      "provenance": [
        {
          "label": "WooCommerce documentation: Order statuses",
          "url": "https://woocommerce.com/document/managing-orders/order-statuses/",
          "checked": "2026-10-11",
          "claims": [
            "Order statuses show what the store knows about a payment, and a Pending payment order has received no payment yet."
          ]
        },
        {
          "label": "WooCommerce documentation: Setting up shipping zones",
          "url": "https://woocommerce.com/document/setting-up-shipping-zones/",
          "checked": "2026-10-11",
          "claims": [
            "Each address matches one shipping zone, first match from the top, and a zone with no methods leaves the shopper with no shipping."
          ]
        },
        {
          "label": "Shopify Help Center: Combining discounts",
          "url": "https://help.shopify.com/en/manual/discounts/discount-combinations",
          "checked": "2026-10-11",
          "claims": [
            "Discounts combine only when both allow it, and customers see a message when codes cannot stack."
          ]
        },
        {
          "label": "Shopify Help Center: Abandoned checkouts",
          "url": "https://help.shopify.com/en/manual/orders/abandoned-checkouts",
          "checked": "2026-10-11",
          "claims": [
            "Shopify lists the cases where no abandoned checkout email is sent."
          ]
        },
        {
          "label": "BigCommerce developer documentation: Webhooks overview",
          "url": "https://docs.bigcommerce.com/developer/docs/integrations/webhooks/overview.md",
          "checked": "2026-10-11",
          "claims": [
            "BigCommerce retries webhook deliveries for 48 hours and then deactivates the webhook."
          ]
        }
      ],
      "related": [
        "guide-woocommerce-variation-attributes-and-any",
        "guide-woocommerce-shipping-zone-order-and-postcodes",
        "guide-shopify-discount-combination-rules",
        "guide-woocommerce-pending-payment-gateway-confirmation",
        "guide-woocommerce-subscription-renewals-scheduler",
        "guide-shopify-abandoned-checkout-when-no-email",
        "guide-bigcommerce-webhook-retries-deactivation",
        "guide-woocommerce-update-test-order-script",
        "example-woocommerce-test-order-matrix",
        "buyer-merchant-ops-store-without-developer",
        "platform-bigcommerce",
        "woo-variable-product-variations-not-selectable",
        "woo-no-shipping-options-for-destination",
        "shopify-discount-code-not-applying-as-intended",
        "woo-orders-stuck-pending-after-payment",
        "woo-subscription-renewals-not-processing",
        "shopify-abandoned-checkout-emails-not-sending",
        "bigcommerce-order-webhook-deactivated-orders-not-syncing",
        "store-recovery-woocommerce-after-failed-update"
      ],
      "sections": [
        {
          "heading": "1. Can the shopper choose and price a product?",
          "body": [
            "Start at the top of the journey with a copy of the store and test data. For every product that matters, choose each option and add it to the cart. A missing size, a \"no products matched\" message or a variation with no price is a data fault in the product, not a checkout fault. The variation guide explains the attribute match, the \"Any\" option and the 30-variation switch."
          ],
          "items": [
            "WooCommerce variable products: the variation guide and the one-product variation repair.",
            "Do not move on until every agreed combination reaches the cart as the right variation."
          ]
        },
        {
          "heading": "2. Does the shopper get a shipping method for each place you serve?",
          "body": [
            "With a sellable cart, enter each destination. No method, or the wrong one, is a zone problem: the order of zones, a zone with no methods, a postcode pattern, or a country that the store settings do not allow. The zone guide shows how WooCommerce picks one zone per address, first match from the top. BigCommerce stores should read the shipping zone and method model in the platform page first."
          ],
          "items": [
            "Test one address inside each zone, one just outside, and one in the catch-all.",
            "Fixed repair: the WooCommerce destination-by-destination shipping job."
          ]
        },
        {
          "heading": "3. Does the discount do exactly what you intended?",
          "body": [
            "Run the baskets that use a code, with and without a second promotion. On Shopify, combination classes, per-customer limits, dates and eligibility explain most refusals. Settle the discount before blaming payment, because a wrong total can look like a payment problem."
          ],
          "items": [
            "Write a basket matrix with expected totals first.",
            "Fixed repair: the Shopify discount-code job, proved on a test store."
          ]
        },
        {
          "heading": "4. Is the payment confirmed back to the store?",
          "body": [
            "Pay with a test method and watch the order status. A payment that succeeds at the provider while the order stays Pending payment is a lost confirmation, not a failed payment. The confirmation guide shows where it is lost: redirects, access rules, a changed address or a deleted webhook. For WooCommerce, do this before looking at renewals or order emails, because both depend on a working confirmation. Shopify recovery emails do not depend on payment confirmation, so a Shopify store can go straight to step 5."
          ],
          "items": [
            "Compare provider payments with order numbers for one day.",
            "Fixed repair: the WooCommerce stuck-order job, proved in test mode."
          ]
        },
        {
          "heading": "5. Do renewals and customer emails happen on time?",
          "body": [
            "For subscriptions, check that renewal orders are created at the due time; the scheduler guide shows what triggers them and why quiet sites run late. For Shopify recovery emails, run the three-scenario test and check the list of cases where no email is sent. If the test email lands in spam, the fault is mail delivery, not the store setting."
          ],
          "items": [
            "Fixed repairs: the subscription renewal job and the abandoned checkout email job."
          ]
        },
        {
          "heading": "6. Does the other system hear about the order?",
          "body": [
            "Last, check that the order reaches the warehouse, accounting or notification system. A notification-based feed can miss or repeat events, and BigCommerce deactivates a webhook after 48 hours of failed retries. Compare order identifiers on both sides before trusting the feed."
          ],
          "items": [
            "Fixed repair: the BigCommerce order webhook job; ongoing: the standing sync check."
          ]
        },
        {
          "heading": "Priced routes, not a package",
          "body": [
            "Each fixed job is its own offer with its own acceptance test. Published test prices, which no buyer has yet responded to: WooCommerce variations £245, shipping zones £195, discount codes £145, abandoned checkout emails £165, stuck orders from £295, subscription renewals from £395 and BigCommerce order webhooks from £345. Payment follows agreed checks and your sign-off, and every price is confirmed in writing before work starts. If several links broke after one event, the recovery project is quoted from £1,750 against a checklist you agree. This sequence is a diagnosis order drawn from the cited platform behaviour, not evidence that anyone has requested or paid for these jobs."
          ],
          "items": [
            "Send a redacted description and the journey that fails; never logins, keys or customer data."
          ]
        }
      ],
      "incoming": [
        "guide-shopify-discount-combination-rules",
        "guide-shopify-abandoned-checkout-when-no-email",
        "guide-woocommerce-shipping-zone-order-and-postcodes",
        "guide-woocommerce-pending-payment-gateway-confirmation",
        "platform-bigcommerce",
        "buyer-merchant-ops-store-without-developer"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/collections/store-checkout-order-flow-diagnosis/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/collections/store-checkout-order-flow-diagnosis/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fcollections%2Fstore-checkout-order-flow-diagnosis%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fcollections%2Fstore-checkout-order-flow-diagnosis%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "collection-store-catalogue-and-stock-integrity",
      "type": "category",
      "title": "Store catalogue and stock integrity: import, structure, stock sync and platform move in order",
      "description": "A diagnosis order for product data and stock problems: bulk import damage, variant structure, stale storefronts, stock drift and catalogue moves, with the paid route for each.",
      "url": "/collections/store-catalogue-and-stock-integrity/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "shopify",
        "wordpress-woocommerce",
        "magento",
        "bigcommerce"
      ],
      "buyer_role": "Owner or merchandiser of an online store who keeps catalogue data and stock figures correct without a developer",
      "purchase_trigger": "Products or stock levels look wrong after an import, a sync run, an update or a platform change",
      "problem": "The operator needs to tell data damage from structure faults, stale display, sync drift and migration mapping before deciding what to buy.",
      "provenance": [
        {
          "label": "Shopify Help Center: Importing products with a CSV file",
          "url": "https://help.shopify.com/en/manual/products/import-export/import-products",
          "checked": "2026-10-11",
          "claims": [
            "Overwrite imports replace values in the columns present, and a blank cell erases a stored value."
          ]
        },
        {
          "label": "Adobe Commerce documentation: Manage the indexers",
          "url": "https://experienceleague.adobe.com/en/docs/commerce-operations/configuration-guide/cli/manage-indexers",
          "checked": "2026-10-11",
          "claims": [
            "In schedule mode a recurring cron job keeps indexes current, so a manual reindex alone is not enough."
          ]
        },
        {
          "label": "Shopify developer documentation: Inventory management apps",
          "url": "https://shopify.dev/docs/apps/build/orders-fulfillment/inventory-management-apps",
          "checked": "2026-10-11",
          "claims": [
            "Stock is held per location in several states, and some state changes do not fire webhooks."
          ]
        },
        {
          "label": "Shopify Help Center: Migrating to Shopify",
          "url": "https://help.shopify.com/en/manual/migrating-to-shopify",
          "checked": "2026-10-11",
          "claims": [
            "Shopify describes CSV and app routes for products and says products are imported first."
          ]
        }
      ],
      "related": [
        "guide-shopify-csv-import-handle-overwrite-blank-cells",
        "example-shopify-product-csv-damage-before-after",
        "guide-woocommerce-variation-attributes-and-any",
        "guide-magento-indexers-schedule-cron-triggers",
        "guide-shopify-inventory-locations-set-versus-adjust",
        "guide-store-reconciling-orders-and-stock-between-systems",
        "example-store-stock-reconciliation-sheet",
        "guide-store-catalogue-move-option-variant-limits",
        "guide-store-redirects-and-launch-checks-after-replatform",
        "buyer-store-owner-moving-platforms",
        "platform-magento",
        "shopify-csv-import-merged-or-overwrote-products",
        "woo-variable-product-variations-not-selectable",
        "magento-catalogue-changes-not-showing-indexers-cron",
        "inventory-shopify-stock-out-of-step-with-connected-system",
        "store-catalogue-mapping-to-shopify-csv",
        "store-keep-order-inventory-sync-healthy"
      ],
      "sections": [
        {
          "heading": "1. Did a bulk import change data it should not have?",
          "body": [
            "If products changed right after an import, start with the files, not the store. Compare the export from before, the file imported and a fresh export. Handles, the overwrite setting, blank cells and missing option columns explain most damage, and the example shows each on invented rows. Do not import again until the comparison is done."
          ],
          "items": [
            "Take a fresh export now as a snapshot.",
            "Paid route: the Shopify import repair, proved on a test store."
          ]
        },
        {
          "heading": "2. Is the product structure itself wrong?",
          "body": [
            "If choices are missing or priced wrongly, check variations, not stock. The WooCommerce variation guide covers attribute matching, the \"Any\" option and the switch at 30 variations. A data repair on one product is different from a redesign of the selector, which is not offered here."
          ],
          "items": [
            "Paid route: the WooCommerce variation repair for one product or one import group."
          ]
        },
        {
          "heading": "3. Is the storefront showing current data?",
          "body": [
            "If the admin is right and shoppers see old data, the fault may be display, not data. On Magento and Adobe Commerce, indexers and a recurring cron job keep the storefront current; the indexer guide gives read-only checks a host can run first. A manual reindex that helps only for a while points at the recurring job."
          ],
          "items": [
            "Paid route: the Magento indexer and cron repair on a staging copy."
          ]
        },
        {
          "heading": "4. Do stock numbers agree across systems?",
          "body": [
            "If Shopify and another system disagree, compare the same state at the same location before suspecting drift: available is not on hand. The reconciliation guide and the example sheet show the method of two lists and a difference, and the inventory guide explains why absolute writes can erase sales."
          ],
          "items": [
            "Paid route: the Shopify stock sync correction for a sync you control."
          ]
        },
        {
          "heading": "5. Are you moving the catalogue to another platform?",
          "body": [
            "A move is a reshaping job: parent and variation rows become handles and variant rows, options are limited to three on Shopify, and old addresses need redirects. The mapping guide shows how WooCommerce and Magento exports read, and the launch guide covers redirects and checks."
          ],
          "items": [
            "Paid route: the product file and redirect file job, or the wider catalogue move project."
          ]
        },
        {
          "heading": "6. Keep it true over time",
          "body": [
            "Once data and stock are right, the standing sync check compares orders and stock every week and explains up to two separate causes of difference a month. It changes nothing in your live systems; the correction is the separate job, and you apply it."
          ],
          "items": []
        },
        {
          "heading": "Priced routes, not a package",
          "body": [
            "Each paid job has its own offer and acceptance test. Published test prices, which no buyer has yet responded to: Shopify import repair from £295, WooCommerce variations £245, Magento indexers from £495, Shopify stock sync from £495, product file and redirects from £695, and the standing sync check £245 a month. The catalogue move project is quoted from £1,500. Payment follows agreed checks and your sign-off. This sequence is a diagnosis order drawn from the cited platform behaviour, not evidence that anyone has requested or paid for these jobs."
          ],
          "items": [
            "Send a redacted description and the first rows of an export; never logins, keys or customer data."
          ]
        }
      ],
      "incoming": [
        "guide-store-reconciling-orders-and-stock-between-systems",
        "guide-store-catalogue-move-option-variant-limits",
        "guide-store-redirects-and-launch-checks-after-replatform",
        "guide-woocommerce-variation-attributes-and-any",
        "guide-magento-indexers-schedule-cron-triggers",
        "platform-magento",
        "buyer-store-owner-moving-platforms"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/collections/store-catalogue-and-stock-integrity/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/collections/store-catalogue-and-stock-integrity/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fcollections%2Fstore-catalogue-and-stock-integrity%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fcollections%2Fstore-catalogue-and-stock-integrity%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "example-xml-feed-first-error-cases",
      "type": "example",
      "title": "Synthetic XML feed cases: five first errors a parser reports and one well-formed file that loses fields",
      "description": "Invented XML snippets with the first error a standard parser reports for each, plus a well-formed namespaced item with CDATA that a text-matching importer misreads.",
      "url": "/examples/xml-feed-first-error-cases/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "xml-feeds"
      ],
      "buyer_role": "Developer or operations manager writing tests for a supplier XML importer",
      "purchase_trigger": "A supplier XML import fails and nobody knows whether the fault is the supplier's file or the importer",
      "problem": "An importer test uses one clean sample, so none of the common first errors are exercised.",
      "related": [
        "xml-supplier-feed-parse-errors-import",
        "platform-xml-feeds"
      ],
      "provenance": [
        {
          "label": "W3C Extensible Markup Language (XML) 1.0, Fifth Edition",
          "url": "https://www.w3.org/TR/xml/",
          "checked": "2026-10-11",
          "claims": [
            "A well-formedness violation is a fatal error that a processor must report; literal < and & must be escaped outside CDATA, comments and processing instructions; end-tag names must match exactly with no case folding; a document has one root element."
          ]
        },
        {
          "label": "Python xml documentation",
          "url": "https://docs.python.org/3/library/xml.html",
          "checked": "2026-10-11",
          "claims": [
            "Attacker-controlled XML can be used for denial of service through entity expansion and compressed bombs."
          ]
        }
      ],
      "sections": [
        {
          "heading": "The invented snippets and their first errors",
          "body": [
            "This is a synthetic worked example with invented values, not a customer case or a supplier's file. Results marked computed were produced with Python's standard library on invented input. Each snippet is two or three lines. The messages below were produced by Python's built-in XML parser; other parsers word them differently, but the position of the first error is the useful part."
          ],
          "items": [],
          "code": "case                         first error reported\nunescaped ampersand           not well-formed (invalid token): line 2, column 18\n  <item><name>Nuts & Bolts</name></item>\nclosing tag in a different case   mismatched tag: line 2, column 19\n  <item><Name>Hinge</name></item>\ncontrol character (U+000B)    not well-formed (invalid token): line 2, column 17\ntext after the root element   junk after document element: line 4, column 0\nbytes not valid in declared UTF-8   not well-formed (invalid token): line 2, column 15\n  (declared utf-8; file bytes were Latin-1)"
        },
        {
          "heading": "A well-formed file that still loses fields",
          "body": [
            "The file below parses without error. The price lives in the Google namespace, and the name is a CDATA section whose text looks like markup and contains an ampersand. A text-matching importer looking for a plain price tag finds none and stores the name with its angle brackets treated as tags. A real parser with the namespace declared returns the price 4.20 GBP and the name Hinge <brass> & steel, as computed."
          ],
          "items": [],
          "code": "<feed xmlns:g=\"http://base.google.com/ns/1.0\">\n<item><g:price>4.20 GBP</g:price>\n<name><![CDATA[Hinge <brass> & steel]]></name></item>\n</feed>\n\nparser result: {g}price = '4.20 GBP'; name = 'Hinge <brass> & steel'"
        },
        {
          "heading": "The assertions an importer test should make",
          "body": [
            "Assert that the well-formed file stores both values exactly. Assert that each broken snippet is rejected as a whole, with the line and column of its first error in the message, and that the stored products are identical before and after the attempt. Assert that a document declaring an entity or an external resource is refused or left unexpanded, because Python's documentation warns that attacker-controlled XML can exhaust memory through entity expansion. These are authored expectations; no supplier's feed was read."
          ],
          "items": []
        },
        {
          "heading": "What this example does not show",
          "body": [
            "It does not show how any supplier produces its XML, nor does it repair a broken file. A file that is not well-formed is the supplier's to correct; the specification treats it as a fatal error, and repairing it by text substitution can store wrong products."
          ],
          "items": []
        },
        {
          "heading": "Use it to specify a priced enquiry",
          "body": [
            "If your importer fails one of these, the fixed job xml-supplier-feed-parse-errors-import is £295 for one importer path and one named supplier layout. Send a redacted sample and the exact parse message first, never real price lists, credentials or code. Prices are untested proposals, and payment follows the agreed checks and your sign-off. Nothing is booked or charged by an enquiry."
          ],
          "items": []
        }
      ],
      "incoming": [
        "platform-xml-feeds"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/xml-feed-first-error-cases/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/examples/xml-feed-first-error-cases/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Fxml-feed-first-error-cases%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fexamples%2Fxml-feed-first-error-cases%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-mapping-supplier-category-unmapped-queue",
      "type": "guide",
      "title": "Supplier categories end up in Uncategorised: use a mapping table with an unmapped list, not loose matching",
      "description": "How to map a supplier's category names to your store categories with one reviewed row per value, an explicit unmapped state, exact matching and a report of new or changed values.",
      "url": "/guides/mapping-supplier-category-unmapped-queue/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "csv-files"
      ],
      "buyer_role": "Merchant or merchandising manager importing supplier catalogues into a store",
      "purchase_trigger": "Many imported products sit in a catch-all category, or a supplier category rename moves products out of place",
      "problem": "Loose text matching or hard-coded cases decide categories, so new or renamed supplier values fall into a default without any record.",
      "related": [
        "mapping-supplier-categories-to-store-categories",
        "guide-supplier-feed-header-drift",
        "platform-csv-files"
      ],
      "provenance": [
        {
          "label": "Google Merchant Center Help: google_product_category",
          "url": "https://support.google.com/merchants/answer/6324436",
          "checked": "2026-10-11",
          "claims": [
            "The attribute takes a predefined Google category as a numeric ID or a full text path, not both, and is single-valued; it is described as optional.",
            "Taxonomy files are published; when no Google category fits or you want your own labels, product_type is the attribute to use."
          ]
        }
      ],
      "sections": [
        {
          "heading": "What goes wrong with loose matching",
          "body": [
            "Category rules often start as a few if-statements: if the supplier category contains hammer, use Hand tools. They work until the supplier adds Hammer drills, renames a category, or sends a path such as Tools > Accessories where Accessories also exists under another parent. Products then land in a default or in a wrong category, and nothing records why. The failure is silent because the import still succeeds."
          ],
          "items": []
        },
        {
          "heading": "A mapping table with one row per supplier value",
          "body": [
            "The replacement is a table, owned by the person who merchandises the store, with one row for each distinct supplier value as it appears in the file, including the whole path where the supplier sends one. Each row has one target store category, a short reason and a state: approved or unmapped. Several supplier values may map to the same store category; one supplier value maps to only one. Matching is exact after a stated normalisation, such as trimming spaces and ignoring letter case, and the normalisation is written down and tested. Anything not found in the table is not matched approximately: it goes to an unmapped list that someone reviews."
          ],
          "items": [
            "Map the full path, not the last segment, whenever the same leaf name occurs under different parents.",
            "Never put an unmapped product in a default category; hold it or import it flagged, as agreed.",
            "Report new and changed values on every run, so a rename is a visible event."
          ]
        },
        {
          "heading": "A second target: Google's category",
          "body": [
            "If the same table also feeds a shopping platform, a second target column can hold the Google category. Google's help page says the google_product_category attribute takes a predefined category as either a numeric ID or a full text path, not both. Because its own examples differ in wording, prefer the numeric ID and check it against the published taxonomy file. The attribute is described as optional, and where no Google category fits, product_type carries your own labels. Do not invent category values; an unknown value is a data problem, not a mapping."
          ],
          "items": []
        },
        {
          "heading": "Other diagnoses to rule out",
          "body": [
            "Products may be in the wrong category because the supplier's own field is wrong, because a different column than the category column was mapped, or because the header changed. If every product is in the default, check the header first. If only new products are affected, the table is missing rows. If categories moved after a supplier rename, the table's keys no longer match exactly."
          ],
          "items": []
        },
        {
          "heading": "A safe first investigation",
          "body": [
            "In a copy of a supplier sample, sort the category column and remove duplicates, or ask your developer to print the distinct values. Look for near-identical spellings, path separators, trailing spaces and different capitalisation. Each distinct text is a separate value the importer must treat consistently. Compare the number of distinct values with the number of rows in your table. A mismatch is your first list of unmapped values."
          ],
          "items": []
        },
        {
          "heading": "How the paid job is accepted",
          "body": [
            "The job mapping-supplier-categories-to-store-categories starts from £395 for up to 200 distinct supplier values, quoted after we see the count and your target list. Every distinct value in the agreed sample must appear once in the table with one target or the unmapped state; a synthetic file with a mapped, a new, a renamed and a many-to-one value must land each product in its target with new and renamed values listed and none placed in a default; and two runs must give the same result. Your named approver signs each mapping row, and we do not decide your merchandising. Prices are untested proposals, and payment follows the agreed checks and your sign-off. Nothing is booked or charged by an enquiry."
          ],
          "items": []
        }
      ],
      "incoming": [
        "platform-csv-files"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/mapping-supplier-category-unmapped-queue/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/mapping-supplier-category-unmapped-queue/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fmapping-supplier-category-unmapped-queue%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fmapping-supplier-category-unmapped-queue%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "platform-csv-files",
      "type": "platform",
      "title": "CSV supplier files: find the first failing layer before changing the importer",
      "description": "For distributors and merchants who import product, stock and price data from CSV: a map of the layers a file passes through, where each fault shows up and which guide or job fits.",
      "url": "/platforms/csv-files/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "csv-files"
      ],
      "buyer_role": "Operations manager, purchasing owner or developer who imports supplier or ERP CSV files",
      "purchase_trigger": "A CSV import produces wrong, shifted, garbled or missing data and nobody knows which layer is at fault",
      "problem": "A CSV file has no schema, so a fault can sit in the bytes, the characters, the rows, the fields or the meaning, and each needs a different fix.",
      "related": [
        "guide-mapping-supplier-category-unmapped-queue",
        "guide-supplier-feed-header-drift",
        "guide-supplier-sku-text-identity",
        "mapping-supplier-categories-to-store-categories"
      ],
      "provenance": [
        {
          "label": "RFC 4180: common format for CSV files",
          "url": "https://www.rfc-editor.org/rfc/rfc4180",
          "checked": "2026-10-11",
          "claims": [
            "It records common CSV practice, is informational, and does not specify an Internet standard; it describes quoting, doubled quotes, an optional header line and an optional charset parameter."
          ]
        },
        {
          "label": "Python csv documentation",
          "url": "https://docs.python.org/3/library/csv.html",
          "checked": "2026-10-11",
          "claims": [
            "Reading depends on the declared delimiter, quote character and encoding, and reader.line_num counts lines, not records."
          ]
        },
        {
          "label": "W3C Metadata Vocabulary for Tabular Data",
          "url": "https://www.w3.org/TR/tabular-metadata/",
          "checked": "2026-10-11",
          "claims": [
            "A dialect declares encoding, delimiter, quote character and header handling explicitly, with stated defaults."
          ]
        }
      ],
      "sections": [
        {
          "heading": "A CSV file promises less than people assume",
          "body": [
            "RFC 4180 is an informational memo that records common practice; it says outright that it does not specify an Internet standard. It describes quoting, doubled quotes and an optional header, and leaves the character set to an optional parameter. Nothing in a CSV file says its delimiter, its encoding or what a value means. The W3C tabular metadata vocabulary exists to declare those things, such as encoding, delimiter and quote character, instead of leaving them to guesswork. For a supplier feed, that declaration is a layout description you write down and keep beside the importer."
          ],
          "items": []
        },
        {
          "heading": "Five layers, five different faults",
          "body": [
            "A file passes through layers, and a fault belongs to exactly one. Bytes to characters: the wrong encoding, or an invisible byte-order mark. Characters to records: line breaks inside quoted fields. Records to fields: delimiters, quotes and doubled quotes. Fields to columns: a header that changed. Columns to meaning: units, identifiers, prices and categories. The quickest diagnosis starts at the first layer and moves up, because a fault low down corrupts everything above it."
          ],
          "items": [
            "Bytes and characters: the guide on encoding and the byte-order mark.",
            "Records and fields: the guide on quotes, delimiters and embedded line breaks.",
            "Columns: the existing guide on header changes.",
            "Meaning: the existing guides on text SKUs, blank prices and pack prices, and the guide on ERP numbers and dates.",
            "Release decision: the guide on comparing two versions by key."
          ]
        },
        {
          "heading": "Where the files come from changes the fix",
          "body": [
            "A supplier file comes from a system you do not control, so the fix is a documented reading rule plus a rejection path and sometimes a request to the supplier. An ERP export is yours, so the fix may be a conversion script with explicit rules for numbers and dates. A spreadsheet in the middle is the most dangerous: opening and re-saving a file can change its encoding, strip leading zeros and reformat numbers, and the original is gone. Keep the original bytes whenever you can."
          ],
          "items": []
        },
        {
          "heading": "What the paid jobs cover",
          "body": [
            "Each fixed job takes one layer and one named layout. Encoding and the byte-order mark: csv-encoding-bom-garbled-characters-import, £195. Quotes, delimiters and line breaks: csv-delimiter-quoting-embedded-newlines-import, £195. A change report between two versions: feed-version-diff-report-before-import, £225. An ERP export converted to your import format: etl-erp-export-to-store-import-transform, from £595. Category mapping: mapping-supplier-categories-to-store-categories, from £395. Image address checks: feed-image-url-validation-before-import, £345. Prices are untested proposals, and payment follows the agreed checks and your sign-off. Nothing is booked or charged by an enquiry."
          ],
          "items": [
            "Each starts from invented or redacted sample rows, not a real price list.",
            "A fault that is in the supplier's data, not your importer, is explained, not fixed."
          ]
        },
        {
          "heading": "Boundaries",
          "body": [
            "This cluster is about non-personal product, stock and price data in files you can lawfully share in redacted form. It does not cover personal data, credentials, live supplier access or repair of data already stored. Send column names, a few invented rows and the importer's name in a first enquiry, and nothing else."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-mapping-supplier-category-unmapped-queue"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/platforms/csv-files/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/platforms/csv-files/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fplatforms%2Fcsv-files%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fplatforms%2Fcsv-files%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "platform-xml-feeds",
      "type": "platform",
      "title": "XML product feeds: well-formed first, then namespaces, then meaning",
      "description": "For distributors and merchants who receive or send product data as XML: why a broken file stops everything, where namespaces and escaping cause quiet loss, and which guide or job fits.",
      "url": "/platforms/xml-feeds/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "xml-feeds"
      ],
      "buyer_role": "Operations manager or developer receiving a supplier XML feed or sending one to a shopping platform",
      "purchase_trigger": "An XML import or an outgoing feed fails with a parse error, or loads items with missing fields",
      "problem": "An XML file must be well-formed before any of its content can be trusted, and namespaces, escaping and encoding each add a way to lose data quietly.",
      "related": [
        "example-xml-feed-first-error-cases",
        "xml-supplier-feed-parse-errors-import"
      ],
      "provenance": [
        {
          "label": "W3C Extensible Markup Language (XML) 1.0, Fifth Edition",
          "url": "https://www.w3.org/TR/xml/",
          "checked": "2026-10-11",
          "claims": [
            "A processor must report a well-formedness violation as a fatal error and not pass data on as normal; the encoding is UTF-8 unless declared or indicated otherwise."
          ]
        },
        {
          "label": "Python xml documentation",
          "url": "https://docs.python.org/3/library/xml.html",
          "checked": "2026-10-11",
          "claims": [
            "Attacker-controlled XML can be used for denial of service; the built-in parsers rely on libexpat."
          ]
        },
        {
          "label": "Google Merchant Center Help: create a product file",
          "url": "https://support.google.com/merchants/answer/160567",
          "checked": "2026-10-11",
          "claims": [
            "Google's XML example uses RSS 2.0 with the g namespace http://base.google.com/ns/1.0 and an item per product."
          ]
        }
      ],
      "sections": [
        {
          "heading": "Two directions, one set of rules",
          "body": [
            "Product data arrives as XML from suppliers and leaves as XML to shopping platforms. The rules of the format are the same in both directions. The XML specification says a file that is not well-formed is a fatal error that a processor must report, and that it must not carry on passing the document's data to the application as normal. A feed with one unescaped ampersand therefore fails as a whole, whoever reads it. The difference is who owns the fix: a supplier's file is theirs to correct, while a file you send to Google is yours."
          ],
          "items": []
        },
        {
          "heading": "Three layers where data is lost",
          "body": [
            "First, well-formedness: escaping, tag matching, character range, a single root, encoding. Second, namespaces and structure: Google's XML example puts product attributes in a g namespace on an RSS item, and an importer that matches tags as text will skip prefixed fields while the file parses cleanly. Third, meaning: whether the values agree with your store, which is a different guide for each platform. The cheapest diagnosis is a real XML parser's first error, with its line and column."
          ],
          "items": [
            "Open a copy in a web browser or run a parser; the first error is more useful than the whole file.",
            "A supplier's XML from an unknown source needs entity-expansion protection; Python's documentation warns about it."
          ]
        },
        {
          "heading": "Where to go next",
          "body": [
            "For a supplier file you read: the guide on well-formed XML and the fixed job xml-supplier-feed-parse-errors-import, £295. For the file you send to Merchant Center: the guide on its format requirements and the fixed job merchant-center-feed-file-fetch-processing-errors, £245. For a file delivered by SFTP that arrives partial or twice: the SFTP guide and sftp-scheduled-supplier-fetch-complete-files, from £445. Prices are untested proposals, and payment follows the agreed checks and your sign-off. Nothing is booked or charged by an enquiry. Google's review and recrawl timing and decisions are its own, and approval is never promised."
          ],
          "items": []
        },
        {
          "heading": "Boundaries",
          "body": [
            "This cluster covers product, stock and price data in feeds you can share in redacted form. We do not repair a supplier's malformed XML by text substitution, design schemas, tune very large files beyond an agreed sample, or take personal data or credentials."
          ],
          "items": []
        }
      ],
      "incoming": [
        "example-xml-feed-first-error-cases"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/platforms/xml-feeds/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/platforms/xml-feeds/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fplatforms%2Fxml-feeds%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fplatforms%2Fxml-feeds%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "platform-google-merchant-center",
      "type": "platform",
      "title": "Google Merchant Center product data: fix the file, then the items, then the images",
      "description": "For merchants whose Shopping products are warned or disapproved: the order in which to diagnose file, price, availability and image problems, and where a data fix ends and Google's review begins.",
      "url": "/platforms/google-merchant-center/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "google-merchant-center"
      ],
      "buyer_role": "Store owner or e-commerce manager responsible for the Merchant Center data source",
      "purchase_trigger": "Products are warned or disapproved, the data source shows errors, or the feed keeps drifting from the site",
      "problem": "Several different causes produce flagged products, and fixing them in the wrong order wastes days waiting for Google to reprocess.",
      "related": [
        "collection-merchant-center-flagged-products-diagnosis-order",
        "buyer-merchant-center-shopping-feed-owner",
        "shopify-merchant-brand-identifier"
      ],
      "provenance": [
        {
          "label": "Google Merchant Center Help: troubleshoot my data source",
          "url": "https://support.google.com/merchants/answer/188476",
          "checked": "2026-10-11",
          "claims": [
            "File-based sources have a processing report with file-level and attribute-level problems; processing catches only basic problems, and the full list of issues is in the Needs attention tab."
          ]
        },
        {
          "label": "Google Merchant Center Help: inaccurate price status",
          "url": "https://support.google.com/merchants/answer/9773429",
          "checked": "2026-10-11",
          "claims": [
            "Update the data after fixing the site, then request a review; a failed review starts a waiting period."
          ]
        },
        {
          "label": "Google Merchant Center Help: inaccurate availability status",
          "url": "https://support.google.com/merchants/answer/9773127",
          "checked": "2026-10-11",
          "claims": [
            "Availability must agree across the landing page, checkout, structured data and the data source."
          ]
        },
        {
          "label": "Google Merchant Center Help: image_link",
          "url": "https://support.google.com/merchants/answer/6324350",
          "checked": "2026-10-11",
          "claims": [
            "Image type, size, address, robots access and content rules are stated on the attribute page."
          ]
        }
      ],
      "sections": [
        {
          "heading": "Start with the order of causes",
          "body": [
            "Google's troubleshooting page says a file-based data source has a processing report covering file-level and attribute-level problems, that processing catches only basic problems, and that the full list of issues is under products that need attention. That implies an order: if the file cannot be fetched or read, nothing else can be seen; once it is read, price and availability mismatches against your pages; then image problems; then identifiers and categories. Account-level suspensions and policy reviews are separate again, and no data fix resolves them. Google's pages as read on 11 October 2026."
          ],
          "items": [
            "File fetch and format: the guides on scheduled fetch and file format.",
            "Price and availability: the guides on price and on availability and refresh timing.",
            "Images: the guide on image_link disapprovals.",
            "Brand and identifiers: the existing fixed job for brand identifier errors on Shopify products."
          ]
        },
        {
          "heading": "What a data fix can and cannot do",
          "body": [
            "A data fix makes the feed accurate and shows it in processed diagnostics. It does not make Google approve a product. Google's pages describe review routes with waiting periods, say a failed review starts a cooldown, and say contacting support does not start a review or extend a deadline. We therefore accept work on processed diagnostics and never on approval, and a product that needs Google's review is listed as such."
          ],
          "items": []
        },
        {
          "heading": "Which paid work fits",
          "body": [
            "File fetch and processing errors on one data source: merchant-center-feed-file-fetch-processing-errors, £245. A price or availability mismatch for up to 25 named products: merchant-center-price-availability-mismatch, £345. Image address checks in your import path: feed-image-url-validation-before-import, £345. Many flags with several causes: merchant-center-clear-disapproved-items, from £1,900, quoted after we see the diagnostics summary. Keeping a data source healthy month to month: merchant-center-keep-feed-approved, £295 a month. Prices are untested proposals, and payment follows the agreed checks and your sign-off. Nothing is booked or charged by an enquiry. Google's review and recrawl timing and decisions are its own, and approval is never promised."
          ],
          "items": []
        },
        {
          "heading": "Boundaries",
          "body": [
            "We never need your Merchant Center login in a first enquiry, or any advertising or billing access. We do not manage campaigns, appeal suspensions, decide prices or stock, or promise approval. First contact is redacted screenshots of the diagnostics, not accounts."
          ],
          "items": []
        }
      ],
      "incoming": [
        "buyer-merchant-center-shopping-feed-owner",
        "collection-merchant-center-flagged-products-diagnosis-order"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/platforms/google-merchant-center/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/platforms/google-merchant-center/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fplatforms%2Fgoogle-merchant-center%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fplatforms%2Fgoogle-merchant-center%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "buyer-feed-operations-manager-supplier-file-delivery",
      "type": "buyer",
      "title": "For an operations manager: make supplier files arrive complete, readable and only once",
      "description": "A page for the person who owns how supplier files are fetched, decoded and imported: what to document, how to describe a failure and which small fixed job or standing check fits.",
      "url": "/buyers/feed-operations-manager-supplier-file-delivery/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "csv-files",
        "sftp"
      ],
      "buyer_role": "Operations manager at a distributor or shop whose supplier files arrive by SFTP, email or download",
      "purchase_trigger": "Some mornings the import has a truncated, repeated or unreadable file and the person who fixed it last time has left",
      "problem": "Delivery, decoding, parsing and release decisions are spread across scripts and people, and nobody owns the whole path.",
      "related": [
        "xml-supplier-feed-parse-errors-import"
      ],
      "provenance": [
        {
          "label": "OpenSSH sftp(1) manual",
          "url": "https://man.openbsd.org/sftp",
          "checked": "2026-10-11",
          "claims": [
            "sftp has a rename command and resume of partial transfers; resuming from a copy that differs from the source is likely to corrupt the file."
          ]
        },
        {
          "label": "RFC 4180: common format for CSV files",
          "url": "https://www.rfc-editor.org/rfc/rfc4180",
          "checked": "2026-10-11",
          "claims": [
            "It describes common practice, is informational, and leaves the character set to an optional parameter."
          ]
        }
      ],
      "sections": [
        {
          "heading": "Write the layout down once",
          "body": [
            "For each supplier, one page: how and when the file arrives, what signals that it is complete, the file type and encoding, the delimiter and quote rule or the XML layout, the key column, and who at the supplier to ask. RFC 4180 records practice rather than a standard, so none of this can be inferred from the file. A written layout is what the next person, and any specialist you hire, needs first."
          ],
          "items": [
            "Where the credentials live and who can rotate them; never in the page itself.",
            "What the importer does with a file it cannot read: reject, hold or partially import."
          ]
        },
        {
          "heading": "Describe a failure so it can be fixed",
          "body": [
            "Say which layer failed: the file did not arrive, arrived partial, was unreadable, was read wrongly or was read right but meant something else. Give an invented or redacted example of the row that failed and what you expected. Say whether the same file fails on a copy. A good description lets a specialist reproduce the fault on a test copy without touching live systems or credentials."
          ],
          "items": []
        },
        {
          "heading": "Which fixed job or standing check fits",
          "body": [
            "Partial, repeated or missing scheduled fetches: sftp-scheduled-supplier-fetch-complete-files, from £445, tested on a synthetic SFTP server. Garbled characters or a lost first column: csv-encoding-bom-garbled-characters-import, £195. Shifted columns from commas, quotes or line breaks: csv-delimiter-quoting-embedded-newlines-import, £195. An XML file that fails or loses fields: xml-supplier-feed-parse-errors-import, £295. A report of what changed before you import: feed-version-diff-report-before-import, £225. A monthly watch over up to three named feeds: import-keep-supplier-feed-import-correct, £395 a month. A whole pipeline rebuilt as one result: feed-rebuild-supplier-feed-pipeline, from £4,500 after a quote. Prices are untested proposals, and payment follows the agreed checks and your sign-off. Nothing is booked or charged by an enquiry."
          ],
          "items": []
        },
        {
          "heading": "What stays with you",
          "body": [
            "You hold supplier credentials and the host key records, you decide what to import, you apply every change and you talk to the supplier. This page does not cover the policy questions of product matching, units and update rules, which the existing page for a distributor's supplier-feed owner covers. Do not send real price lists, credentials or private code in a first enquiry."
          ],
          "items": []
        }
      ],
      "incoming": [],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/buyers/feed-operations-manager-supplier-file-delivery/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/buyers/feed-operations-manager-supplier-file-delivery/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fbuyers%2Ffeed-operations-manager-supplier-file-delivery%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fbuyers%2Ffeed-operations-manager-supplier-file-delivery%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "buyer-merchant-center-shopping-feed-owner",
      "type": "buyer",
      "title": "For a merchant with flagged Shopping products: find the cause group before you edit the feed",
      "description": "A page for the person who owns the Merchant Center data source: what to collect, how to sort flagged products by cause and which fixed job, project or monthly watch fits.",
      "url": "/buyers/merchant-center-shopping-feed-owner/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "google-merchant-center"
      ],
      "buyer_role": "Store owner or e-commerce manager who owns the Merchant Center data source and the site's prices and stock",
      "purchase_trigger": "Products are flagged after a sale, a relaunch or a feed change and different diagnostics name different reasons",
      "problem": "Flags come from several causes at once, and editing the feed without sorting them first wastes review cycles.",
      "related": [
        "collection-merchant-center-flagged-products-diagnosis-order",
        "platform-google-merchant-center"
      ],
      "provenance": [
        {
          "label": "Google Merchant Center Help: inaccurate price status",
          "url": "https://support.google.com/merchants/answer/9773429",
          "checked": "2026-10-11",
          "claims": [
            "Check the example products in the warning, correct the data, resubmit it and request a review; a failed review starts a waiting period."
          ]
        },
        {
          "label": "Google Merchant Center Help: add products from a file",
          "url": "https://support.google.com/merchants/answer/12158380",
          "checked": "2026-10-11",
          "claims": [
            "A scheduled file is fetched every 24 hours by default."
          ]
        }
      ],
      "sections": [
        {
          "heading": "Collect three things first",
          "body": [
            "A redacted summary of the diagnostics: the issue names and roughly how many products each affects. The way the feed is produced and when it last refreshed. And which of your systems is the authority for price and stock. Without the third, any fix risks making the feed match a page that is itself wrong. Do not send logins, advertising access or customer data; redacted screenshots are enough to start."
          ],
          "items": []
        },
        {
          "heading": "Sort by cause, not by product",
          "body": [
            "Hundreds of flagged products rarely have hundreds of causes. Google's help pages name the usual ones: a file that cannot be fetched or read, a price or availability that differs from the page, images that break the rules, and identifiers or categories. Group the flagged products by the issue name, then fix in order: file, price and availability, images, identifiers. Each group has one cause and one fix, and each fix shows in processed diagnostics, not in a promise from anyone."
          ],
          "items": []
        },
        {
          "heading": "Which paid route fits",
          "body": [
            "One failing data source file is covered by merchant-center-feed-file-fetch-processing-errors, £245. A price or availability mismatch for up to 25 named products: merchant-center-price-availability-mismatch, £345. Several causes at once and a defined list to clear: merchant-center-clear-disapproved-items, from £1,900 after we see the diagnostics summary. Watching the source month after month: merchant-center-keep-feed-approved, £295 a month. Prices are untested proposals, and payment follows the agreed checks and your sign-off. Nothing is booked or charged by an enquiry. Google's review and recrawl timing and decisions are its own, and approval is never promised."
          ],
          "items": []
        },
        {
          "heading": "What stays with you",
          "body": [
            "You keep your account, your prices and promotions, and the decision to apply every change, resubmit the data and request any review. We do not hold advertising or billing access, appeal suspensions, decide your prices or stock, or promise approval. If your account is suspended or cites misrepresentation, follow Google's account route first; a data fix is the wrong tool."
          ],
          "items": []
        }
      ],
      "incoming": [
        "platform-google-merchant-center",
        "collection-merchant-center-flagged-products-diagnosis-order"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/buyers/merchant-center-shopping-feed-owner/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/buyers/merchant-center-shopping-feed-owner/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fbuyers%2Fmerchant-center-shopping-feed-owner%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fbuyers%2Fmerchant-center-shopping-feed-owner%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "collection-merchant-center-flagged-products-diagnosis-order",
      "type": "category",
      "title": "Merchant Center products flagged: work through account, file, price, stock, images and review in order",
      "description": "An ordered process map for flagged Shopping products: separate account-level issues from item issues, then fix file fetch and format, price and availability, images and identifiers, then plan the refresh route and review.",
      "url": "/collections/merchant-center-flagged-products-diagnosis-order/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "google-merchant-center"
      ],
      "buyer_role": "Store owner or e-commerce manager triaging Merchant Center warnings before editing the feed",
      "purchase_trigger": "Many products are flagged for different reasons and each fix seems to reveal another",
      "problem": "Without an order, fixes are made in a sequence that hides their own results.",
      "related": [
        "platform-google-merchant-center",
        "buyer-merchant-center-shopping-feed-owner",
        "shopify-merchant-brand-identifier"
      ],
      "provenance": [
        {
          "label": "Google Merchant Center Help: troubleshoot my data source",
          "url": "https://support.google.com/merchants/answer/188476",
          "checked": "2026-10-11",
          "claims": [
            "Processing catches only basic file and data problems; the full list of issues is in the Needs attention tab under Products."
          ]
        },
        {
          "label": "Google Merchant Center Help: inaccurate price status",
          "url": "https://support.google.com/merchants/answer/9773429",
          "checked": "2026-10-11",
          "claims": [
            "Fix steps are to correct the data, resubmit it and request a review; a failed review starts a waiting period before another request."
          ]
        },
        {
          "label": "Google Merchant Center Help: inaccurate availability status",
          "url": "https://support.google.com/merchants/answer/9773127",
          "checked": "2026-10-11",
          "claims": [
            "After fixing, resubmit, check diagnostics and request a review; the page says a fresh crawl usually finishes in 24 to 48 hours."
          ]
        }
      ],
      "sections": [
        {
          "heading": "1. Is it the account or the items?",
          "body": [
            "Read the message. An account-level suspension, a misrepresentation review or a policy notice is not fixed by editing product data, and changing prices to chase it can make things worse. Item-level issues are what the rest of this order handles. If the account message is the only problem, follow Google's account route."
          ],
          "items": []
        },
        {
          "heading": "2. Can Google fetch the file?",
          "body": [
            "If the data source's report shows a failed fetch, nothing at item level can be seen. Check the address, access, redirects and schedule. The scheduled fetch guide covers it; the fixed job is merchant-center-feed-file-fetch-processing-errors, £245."
          ],
          "items": []
        },
        {
          "heading": "3. Can Google read the file?",
          "body": [
            "File-level errors in the latest-update report come from format, header, tabs, XML escaping, tag case, extension, compression or encoding. The file format guide covers each. Compare the items read with the rows in your file."
          ],
          "items": []
        },
        {
          "heading": "4. Do price and availability match the page?",
          "body": [
            "For each flagged product compare feed, page, checkout and markup for the same country and variant. Tax inclusion, stale feeds, variants, sale prices and stock changes explain most mismatches. The guides on price and on availability and refresh timing cover them; the fixed job is merchant-center-price-availability-mismatch, £345."
          ],
          "items": [
            "Correct the data, resubmit, then request a review; a failed review starts a waiting period.",
            "A fresh crawl after a fix usually takes one to two days according to Google's page."
          ]
        },
        {
          "heading": "5. Are the images acceptable?",
          "body": [
            "Image issues are type, size, address, access and content. The image guide separates them, and the generic address-check guide shows how to classify links before products reach the feed. For flagged images in the file you send to Merchant Center, the work sits inside merchant-center-clear-disapproved-items, from £1,900, which checks addresses, types and sizes and lists pictures that need replacing, such as overlays or placeholders, as needing your action. If the bad addresses arrive in a supplier feed that you import, the fixed job is feed-image-url-validation-before-import, £345; it cannot judge overlays or placeholders."
          ],
          "items": []
        },
        {
          "heading": "6. Identifiers and categories",
          "body": [
            "Brand, product identifiers and category values are separate fault families. For Shopify products rejected for missing brand identifiers, the existing fixed job shopify-merchant-brand-identifier covers it; do not invent identifiers."
          ],
          "items": []
        },
        {
          "heading": "7. Plan the refresh route, then the watch",
          "body": [
            "Once the data is right, keep it right: a written refresh route so price and stock changes reach the feed within a stated time, then a regular look at diagnostics. For a defined body of flags with several causes, merchant-center-clear-disapproved-items starts from £1,900 after a quote; to watch a data source month by month, merchant-center-keep-feed-approved is £295 a month. Prices are untested proposals, and payment follows the agreed checks and your sign-off. Nothing is booked or charged by an enquiry. Google's review and recrawl timing and decisions are its own, and approval is never promised."
          ],
          "items": []
        }
      ],
      "incoming": [
        "platform-google-merchant-center",
        "buyer-merchant-center-shopping-feed-owner"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/collections/merchant-center-flagged-products-diagnosis-order/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/collections/merchant-center-flagged-products-diagnosis-order/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fcollections%2Fmerchant-center-flagged-products-diagnosis-order%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fcollections%2Fmerchant-center-flagged-products-diagnosis-order%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-membership-builder-tools-what-they-cannot-do",
      "type": "guide",
      "title": "Members-only pages on Wix, Squarespace and Webflow: what each builder's own tools can and cannot do",
      "description": "Wix and Squarespace each have a built-in members feature with different rules. Webflow no longer has one. This guide sets out how each works and the limits worth knowing before you promise anyone privacy.",
      "url": "/guides/membership-builder-tools-what-they-cannot-do/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "wix",
        "squarespace",
        "webflow"
      ],
      "buyer_role": "Owner who wants chosen people to see some pages on a builder-hosted site",
      "purchase_trigger": "Private content is currently public or sent by email and you want a single members-only place",
      "problem": "A members area is configured with the builder's tool but the tool's limits are not known, so a page stays public or a promise of secrecy cannot be kept.",
      "related": [
        "stripe-memberstack-access-after-payment"
      ],
      "provenance": [
        {
          "label": "Wix: creating members-only pages",
          "url": "https://support.wix.com/en/article/wix-editor-creating-members-only-pages",
          "checked": "2026-10-11",
          "claims": [
            "A Members Area must be added first, and a page can be limited to all members or to specific roles or pricing plans; site collaborators can still reach every page by default."
          ]
        },
        {
          "label": "Squarespace: member sites",
          "url": "https://support.squarespace.com/hc/en-us/articles/360050832631-Member-Sites",
          "checked": "2026-10-11",
          "claims": [
            "A member site needs a pricing plan, pages in a member site have SEO settings off and are left out of the sitemap, moving a page out or deleting the member site makes it public, and Squarespace cannot guarantee content security once access is granted."
          ]
        },
        {
          "label": "Squarespace: managing members",
          "url": "https://support.squarespace.com/hc/en-us/articles/360050832691-Managing-members",
          "checked": "2026-10-11",
          "claims": [
            "Member contacts cannot be created or imported manually, and you cannot sign someone up for a plan on their behalf."
          ]
        },
        {
          "label": "Webflow: User Accounts sunset",
          "url": "https://help.webflow.com/hc/en-us/articles/36046006227731-User-Accounts-sunset",
          "checked": "2026-10-11",
          "claims": [
            "Webflow's User Accounts feature was shut down on 29 January 2026, removing content gates and member login on published sites."
          ]
        }
      ],
      "sections": [
        {
          "heading": "Wix: a members area, then page access",
          "body": [
            "On Wix, the Members Area comes first. You add it to the site first. Only then can you restrict a page. In the editor you open the page's settings, find the access tab, choose Site Members, and pick who may enter: all members, or specific members by role, by pricing plan, or both.",
            "One default catches people out. The toggle that lets site collaborators reach every page is on by default, so you and your collaborators see everything while testing. Test with a separate member account, not your own, or you will not see what a real member sees."
          ],
          "items": [
            "Add the Members Area before touching page settings.",
            "Test with an account that is not a collaborator.",
            "Review who holds which role after any change."
          ]
        },
        {
          "heading": "Squarespace: member sites and pricing plans",
          "body": [
            "Squarespace builds a members area as a member site: you group pages into it and attach it to a pricing plan. It is free to build, but selling memberships needs a website plan, and a member site must be attached to a pricing plan or visitors who try to log in are told the product is unavailable. A page can belong to only one member site, and member sites do not support dropdown menus.",
            "Three limits matter before you promise anything. Member pages have their SEO settings turned off and are left out of the sitemap. If you delete the member site or move a page out of it, that page becomes unrestricted and visible to search engines, and anyone with the link can open it. And contacts cannot be created or imported manually: people have to register themselves for a plan, so existing members from another platform must sign up again."
          ],
          "items": [
            "Plan the message that tells existing members to re-register.",
            "Re-test every protected address after moving any page.",
            "Do not treat a deleted member site as a way to hide pages."
          ]
        },
        {
          "heading": "Webflow: no native members feature now",
          "body": [
            "Webflow's own User Accounts feature, formerly called Memberships, could not be enabled on new sites from 31 January 2025 and was shut down on 29 January 2026. Webflow says content gates were removed and members can no longer log in on published sites, and the data was not migrated into the CMS. Paid subscriptions held in a connected Stripe account continue there, which makes a replacement urgent for affected sites.",
            "A members area on Webflow therefore needs a third-party service. That is a different build with its own cost and its own rules, and it is outside the fixed-scope job for Wix and Squarespace."
          ],
          "items": [
            "If your Webflow site used User Accounts, check what is public now.",
            "Choose a replacement service before the content is relied on.",
            "Treat any gating tool as a convenience, not a vault."
          ]
        },
        {
          "heading": "What no builder tool guarantees, and acceptance",
          "body": [
            "Squarespace is explicit that it cannot guarantee the security of content once access has been granted, and the same is true of any builder: a member can copy or share what they have seen. If a page must stay secret for commercial or legal reasons, a builder's membership tool is the wrong choice.",
            "The fixed-scope job on Wix or Squarespace is priced at £645 for up to five protected pages and two access levels as an untested proposal, paid only after you sign off. It is accepted when each protected address shows nothing to a logged-out visitor, a test member with the right level sees every page meant for it, a signed-in non-member sees none of the restricted pages, and removing the test member's access closes them again."
          ],
          "items": []
        }
      ],
      "incoming": [],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/membership-builder-tools-what-they-cannot-do/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/membership-builder-tools-what-they-cannot-do/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fmembership-builder-tools-what-they-cannot-do%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fmembership-builder-tools-what-they-cannot-do%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "example-wordpress-members-access-matrix",
      "type": "example",
      "title": "Synthetic example: a members-only access matrix with one leak that only appears from the cache",
      "description": "An invented test grid for a made-up course site, showing expected and actual access and the cached sequence that exposes a fault.",
      "slug": "wordpress-members-access-matrix",
      "url": "/examples/wordpress-members-access-matrix/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "wordpress",
        "wordpress-plugins"
      ],
      "provenance": [
        {
          "label": "Paid Memberships Pro documentation: caching",
          "url": "https://www.paidmembershipspro.com/documentation/advanced/caching/",
          "checked": "2026-10-11",
          "claims": [
            "Caching protected content can show it to non-members; excluding member-protected content from the cache or disabling caching for logged-in users is recommended by that vendor."
          ]
        },
        {
          "label": "WordPress REST API handbook: authentication",
          "url": "https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/",
          "checked": "2026-10-11",
          "claims": [
            "Without a nonce the current user is set to 0 and the request is treated as unauthenticated."
          ]
        }
      ],
      "related": [
        "guide-wordpress-members-only-content-caching-and-data-routes",
        "stripe-memberstack-access-after-payment"
      ],
      "sections": [
        {
          "heading": "The invented site",
          "body": [
            "A made-up online course site has four test accounts and four protected items. All accounts are fake and exist only on a staging copy. The items are a free preview page, a Level 1 lesson page, a Level 2 lesson page and a Level 2 downloadable workbook. Expected results are written before testing. Everything below is invented to show a method."
          ],
          "items": [
            "Accounts: logged-out, Level 1 member, Level 2 member, expired member.",
            "Items: preview, lesson 1, lesson 2, workbook file address."
          ]
        },
        {
          "heading": "The grid",
          "body": [
            "Each cell shows expected, then actual. \"ok\" means they match. Anything else is a finding."
          ],
          "items": [
            "A = allowed, D = denied. Read each cell as expected/actual."
          ],
          "code": "account         | preview | lesson 1 | lesson 2 | workbook\nlogged-out      | A/A ok  | D/D ok   | D/D ok   | D/A  <- finding\nLevel 1 member  | A/A ok  | A/A ok   | D/D ok   | D/D ok\nLevel 2 member  | A/A ok  | A/A ok   | A/A ok   | A/A ok\nexpired member  | A/A ok  | D/A  <-  | D/D ok   | D/D ok"
        },
        {
          "heading": "Reading the findings",
          "body": [
            "Two cells fail. A logged-out visitor can fetch the workbook through its direct file address, which means the page that links to the file is protected but the file is not. An expired member still reads lesson 1, which suggests their level expiry did not apply, a task a scheduler may have missed or a role that was not updated. The grid does not say which; it shows where to look next. The fix for each goes on a staging copy first, then the grid is run again in full."
          ],
          "items": [
            "A protected page does not automatically protect the file it links to; test the file address.",
            "An expired level that still has access points to the expiry mechanism or to caching."
          ]
        },
        {
          "heading": "The sequence that exposes caching",
          "body": [
            "A second test makes three requests to lesson 2 in a row on a staging copy with page caching enabled as on the live site: logged-out, then Level 2 member, then logged-out again. Expected: deny, allow, deny. Actual in this invented run: deny, allow, allow. The second logged-out request received the member's cached copy. That is a caching fault, not a rule fault, and no amount of editing the access rules would fix it."
          ],
          "items": [
            "Run the sequence at least twice, with the cache cleared before the first.",
            "Record what each response actually contained, not only the status."
          ]
        },
        {
          "heading": "What this example does not prove",
          "body": [
            "It is not a real site, test or fault, and the cells are invented. A passing grid is evidence for the cells tested, not a guarantee that nothing leaks, and it cannot recall copies of content others already hold. Real tests also cover archives, search, feeds and the data interface for a logged-out request. The workbook finding is realistic only as an illustration of testing the file address separately."
          ],
          "items": [
            "Do not infer that your site has either fault."
          ]
        },
        {
          "heading": "Use it to specify an enquiry",
          "body": [
            "Send the membership plugin's name, the account types, the items to protect and examples of wrong access. The access job has a published test price of GBP 395 for one plugin, up to four levels and ten items, using made-up accounts on staging. If members paid but their level did not change, the payment-to-access job fits better. Prices are untested proposals and payment follows the agreed checks."
          ],
          "items": [
            "Send lists and descriptions, never real member data."
          ]
        }
      ],
      "incoming": [
        "guide-wordpress-members-only-content-caching-and-data-routes"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/wordpress-members-access-matrix/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/examples/wordpress-members-access-matrix/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Fwordpress-members-access-matrix%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fexamples%2Fwordpress-members-access-matrix%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-wordpress-members-only-content-caching-and-data-routes",
      "type": "guide",
      "title": "Members-only WordPress content visible to the wrong people: check caching, roles and the other routes",
      "description": "Why access rules can pass in the admin and still fail in practice: page caches, role changes that do not apply, and routes such as the REST data interface.",
      "slug": "wordpress-members-only-content-caching-and-data-routes",
      "url": "/guides/wordpress-members-only-content-caching-and-data-routes/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "wordpress",
        "wordpress-plugins"
      ],
      "provenance": [
        {
          "label": "Paid Memberships Pro documentation: caching",
          "url": "https://www.paidmembershipspro.com/documentation/advanced/caching/",
          "checked": "2026-10-11",
          "claims": [
            "Caching protected content can show it to non-members and can stop members seeing what they paid for; exclude the plugin's pages, log-in and password-reset pages from the cache; disable caching for logged-in users or exclude member-protected content; payment gateway webhook addresses must stay uncached; the object cache may need clearing after restrictions change."
          ]
        },
        {
          "label": "WordPress REST API handbook: posts reference",
          "url": "https://developer.wordpress.org/rest-api/reference/posts/",
          "checked": "2026-10-11",
          "claims": [
            "A list request defaults to the publish status; the context parameter takes view, embed or edit and defaults to view; the password parameter is documented for retrieving password-protected posts; the page does not say who may use the edit context."
          ]
        },
        {
          "label": "WordPress REST API handbook: authentication",
          "url": "https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/",
          "checked": "2026-10-11",
          "claims": [
            "Cookie authentication needs a nonce, and without a nonce the current user is set to 0 and the request is treated as unauthenticated; application passwords have shipped since WordPress 5.6 and are sent as Basic Auth over https."
          ]
        },
        {
          "label": "WordPress plugin handbook: roles and capabilities",
          "url": "https://developer.wordpress.org/plugins/users/roles-and-capabilities/",
          "checked": "2026-10-11",
          "claims": [
            "Roles and capabilities are stored in the options table under user_roles; after the first add_role() call the role is saved and later calls do nothing, including attempts to change capabilities; changing them in bulk means remove_role() then add_role()."
          ]
        }
      ],
      "related": [
        "example-wordpress-members-access-matrix",
        "stripe-memberstack-access-after-payment"
      ],
      "sections": [
        {
          "heading": "Four layers must agree",
          "body": [
            "Members-only content is protected by a chain: the membership plugin's rule on each item, the level each user holds, any cache that stores a copy of the page, and every other route by which the same content can be requested. Testing in the admin as an administrator tests none of them properly, because administrators usually see everything. A reliable check names the account types, names the items, states for every pair whether access should be allowed or denied, and then tests each pair from a clean browser profile. That table is the access matrix, and it is the only artefact that lets two people agree on what \"fixed\" means."
          ],
          "items": [
            "Rows: logged-out visitor, each level, an expired member, an administrator.",
            "Columns: each protected item, including downloads.",
            "Cells: expected and actual result."
          ]
        },
        {
          "heading": "Caches are the usual cause of strange access",
          "body": [
            "A membership vendor's caching guide states the problem directly: cached protected content can be seen by non-members, and members can be left unable to view what they paid for. Its advice is to exclude the plugin's own pages and the log-in and password-reset pages from the cache, and either disable caching for logged-in users or exclude all member-protected content. It also says payment gateway webhook addresses must stay uncached, that some hosts cache only for frequent callers so the address looks fine when you test it yourself, and that after changing restrictions you may need to clear the object cache. This is one vendor's documentation for its own plugin, so check your plugin's own guidance, but the pattern applies broadly: test with the cache on, as it is live, and with sequences such as logged-out, member, logged-out."
          ],
          "items": [
            "Ask your host which cache layers exist; many hosts cache without any plugin.",
            "Staging without the live cache can pass while live fails."
          ]
        },
        {
          "heading": "Other routes to the same content",
          "body": [
            "WordPress exposes content through more than one route: archives, search results, feeds and a data interface called the REST API. The posts reference says a list request defaults to published posts, that a context parameter takes view, embed or edit with view as the default, and documents a password parameter for password-protected posts. It does not say who may use the edit context, and it does not describe what a membership plugin changes, so the safe course is to test rather than assume. The authentication handbook explains that cookie authentication needs a nonce, and that without one the current user is set to zero and the request is unauthenticated, which is the situation of a logged-out visitor. Application passwords, available since WordPress 5.6, are for remote clients over https."
          ],
          "items": [
            "As a logged-out visitor, request the data-interface address of one protected item and read the response body.",
            "Search for a protected title while logged out and see what the results show.",
            "For downloads, request the file address itself and report what happens."
          ]
        },
        {
          "heading": "Role changes made in code may not apply",
          "body": [
            "The roles and capabilities handbook has a detail that explains many staging-versus-live differences. Roles are stored in the database, and after the first add_role() call the role is saved there; later calls do nothing, including attempts to change its capabilities. Changing capabilities in bulk means removing the role and adding it again, which the handbook warns should be done only when the capabilities differ because of the performance cost. A capability change deployed in code can therefore have no effect on a site whose database already holds the role. Check what the database holds, not only what the code says."
          ],
          "items": [
            "Compare the capabilities of each role on staging and live.",
            "Treat \"works on my copy\" with suspicion if the copy came from a different database."
          ]
        },
        {
          "heading": "Fit, limits and the paid job",
          "body": [
            "This guide cannot show that nothing leaks; it shows where to look. The access job has a published test price of GBP 395 for one membership plugin, up to four levels and ten items, on a staging copy with made-up accounts. It is accepted when every cell of the matrix passes, a cached sequence returns the right result each time, other routes show no restricted body text for a logged-out request, and the live views match after your site holder applies the settings. It does not repair payment-to-access sync, switch plugins or give legal advice, and it cannot recall copies others already hold. Prices are untested proposals and payment follows the agreed checks."
          ],
          "items": [
            "If members paid but their level did not change, the fault is in the payment sync.",
            "If confidential material is exposed now, take it offline first and fix it second."
          ]
        }
      ],
      "incoming": [
        "example-wordpress-members-access-matrix"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/wordpress-members-only-content-caching-and-data-routes/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/wordpress-members-only-content-caching-and-data-routes/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fwordpress-members-only-content-caching-and-data-routes%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fwordpress-members-only-content-caching-and-data-routes%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "example-supplier-key-collision-matrix",
      "type": "example",
      "title": "Synthetic supplier-key matrix: zeros, long codes, reused SKUs and an unmapped item",
      "description": "Four invented product mappings expose numeric coercion and cross-supplier collisions; an unknown key stays unassigned instead of becoming a guessed product.",
      "url": "/examples/supplier-key-collision-matrix/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds",
        "csv"
      ],
      "buyer_role": "Purchasing manager reviewing how an importer matches supplier products",
      "purchase_trigger": "Different supplier items land on the same internal product",
      "problem": "A matching test contains only ordinary identifiers and never exercises the source-key boundary.",
      "related": [
        "guide-supplier-sku-text-identity",
        "guide-supplier-key-namespace",
        "collection-supplier-feed-import-checks"
      ],
      "provenance": [
        {
          "label": "Python CSV reader preserves strings by default",
          "url": "https://docs.python.org/3/library/csv.html",
          "checked": "2026-10-11",
          "claims": [
            "QUOTE_NONNUMERIC changes unquoted fields to floats, unlike default string reading."
          ]
        },
        {
          "label": "PostgreSQL composite-key constraints",
          "url": "https://www.postgresql.org/docs/current/ddl-constraints.html",
          "checked": "2026-10-11",
          "claims": [
            "Composite uniqueness applies to the combined column values."
          ]
        },
        {
          "label": "Current bug-repair scope",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "The invented mapping",
          "body": [
            "Alder and Birch are made-up supplier labels. The example's declared policy uses supplier plus exact text SKU; it does not trim, case-fold or turn a code into a number. The internal product IDs are invented and contain no people or client records."
          ],
          "items": [],
          "code": "supplier | SKU text          | expected internal product\nalder    | 00123             | part-a\nalder    | 123               | part-b\nbirch    | 00123             | part-c\nalder    | 9007199254740993  | part-d\nbirch    | 123               | unmapped; no automatic creation"
        },
        {
          "heading": "Expected checks",
          "body": [
            "The first two rows stay separate despite looking numeric. The first and third stay separate despite an equal local SKU. The long code remains the exact string shown. The last lookup is unmapped and reports an exception. These are expected results under the authored policy, not observations from a supplier import."
          ],
          "items": [
            "A numeric 123 supplied where a text SKU is required is an invalid input in this example.",
            "No existing record is changed to satisfy the mapping.",
            "A real supplier's rules for spaces or letter case must be agreed separately."
          ]
        },
        {
          "heading": "What it does not prove",
          "body": [
            "The batch's local policy model tests these invented lookups. It is not a CSV parser, spreadsheet application, product-equivalence engine or database constraint test. It does not show that an upstream spreadsheet preserved the original source identifier, or that a supplier mapping is correct for physical goods. Do not infer production reliability or previous SI delivery."
          ],
          "items": [
            "Recover already damaged identifiers from an authoritative source rather than padding them by guesswork.",
            "Keep unknown product mapping under the purchasing owner's approval."
          ]
        },
        {
          "heading": "Use this to specify a priced enquiry",
          "body": [
            "Describe which synthetic lookup fails and the desired key. One existing local matching defect may fit fix-one-bug-with-regression-test, from £295 after bounded reproduction and a fixed repair quote. Historical catalogue cleanup, a new master-data system and schema migration are outside the repair. No code, real price lists, private exports or credentials in first contact; the price is untested and payment follows passing checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-supplier-sku-text-identity",
        "guide-supplier-key-namespace"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/supplier-key-collision-matrix/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/examples/supplier-key-collision-matrix/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Fsupplier-key-collision-matrix%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fexamples%2Fsupplier-key-collision-matrix%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "example-supplier-update-presence-contract",
      "type": "example",
      "title": "Synthetic supplier-update contract: blank price, absent field and missing product",
      "description": "A worked decision matrix separates a field omitted from a partial update from a product absent from a complete snapshot, with explicit hold and no-change results.",
      "url": "/examples/supplier-update-presence-contract/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds"
      ],
      "buyer_role": "Stock-control or purchasing manager approving destructive import semantics",
      "purchase_trigger": "A partial update clears a price or marks omitted items unavailable",
      "problem": "The application needs an owner-approved policy at both the field-presence and feed-coverage boundaries.",
      "related": [
        "guide-supplier-blank-price-update",
        "guide-supplier-snapshot-versus-delta",
        "collection-supplier-feed-import-checks"
      ],
      "provenance": [
        {
          "label": "Python CSV missing-field and None serialization behaviour",
          "url": "https://docs.python.org/3/library/csv.html",
          "checked": "2026-10-11",
          "claims": [
            "Missing row fields and explicitly empty strings can differ on read; writing None as an empty string loses that distinction."
          ]
        },
        {
          "label": "W3C tabular metadata: declared null markers",
          "url": "https://www.w3.org/TR/tabular-metadata/",
          "checked": "2026-10-11",
          "claims": [
            "Metadata can declare null markers; the default null marker is an empty string."
          ]
        },
        {
          "label": "Current local-repair terms",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        },
        {
          "label": "Current preview-feature terms",
          "url": "https://syntheticindustry.ai/services/ship-one-feature-with-running-preview/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Field-presence policy, starting price 12.50",
          "body": [
            "The following is a synthetic patch contract chosen for this example. A deliberately absent optional price is unchanged. A short CSV row is malformed and must be rejected before this contract is applied; it is not the deliberately absent case. Zero prices are prohibited only by this example's stated purchasing rule."
          ],
          "items": [],
          "code": "submitted state                  | disposition  | price after\noptional price deliberately absent| unchanged    | 12.50\nprice present, empty string       | hold-blank   | 12.50\nprice present, 0.00               | hold-zero    | 12.50\nprice present, 13.25              | replace      | 13.25\nexplicit authorised clear        | clear        | null\nexplicit clear without authority | hold-clear   | 12.50"
        },
        {
          "heading": "Product-absence policy, three existing products",
          "body": [
            "The existing set is part-a, part-b and part-c. The incoming feed contains part-a only. Declared coverage is part-a and part-b, so part-c is outside scope. A confirmed complete snapshot marks part-b unavailable under this authored rule; it never deletes it or declares discontinuation. A delta leaves omitted products unchanged."
          ],
          "items": [],
          "code": "feed mode and completion    | disposition       | mark unavailable | unchanged\ndelta, complete update      | accept            | none             | part-b, part-c\nsnapshot, complete          | accept            | part-b           | part-c\nsnapshot, incomplete        | hold-completeness | none             | part-a, part-b, part-c\nunknown mode                | hold-mode         | none             | part-a, part-b, part-c"
        },
        {
          "heading": "Limits and acceptance",
          "body": [
            "The local authored model tests these dispositions with invented values. It does not parse a file, validate supplier completeness, execute database writes or recover a real import. In an actual application test, compare prior and resulting state for every rejected case, not merely the returned status. Approve the purchasing rule before implementing it."
          ],
          "items": [
            "An empty CSV value has no universal business meaning.",
            "No stock, prices or accounts were changed.",
            "A source-completeness declaration needs authoritative evidence for the exact coverage."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "An existing local field-presence bug may fit the regression-test repair from £295 after bounded reproduction and a fixed quote. One new change-preview interaction may fit the feature-preview offer from £750 only in an existing app with an already available isolated private preview, synthetic data and no sensitive handling changes. Do not bundle both into one assumed small job. Live feed retrieval, stock publication, data recovery and a new inventory system are excluded. Send invented prior state, submitted state and desired disposition, not files or credentials; prices are untested and payment follows agreed checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-supplier-blank-price-update",
        "guide-supplier-snapshot-versus-delta"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/supplier-update-presence-contract/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/examples/supplier-update-presence-contract/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Fsupplier-update-presence-contract%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fexamples%2Fsupplier-update-presence-contract%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "example-supplier-pack-price-calculation",
      "type": "example",
      "title": "Worked pack-price example: why 36 items cost 59.97, not the rounded display total",
      "description": "An invented USD 19.99 pack of 12 distinguishes the purchase basis from a rounded per-item comparison and shows exactly where a misleading total arises.",
      "url": "/examples/supplier-pack-price-calculation/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds"
      ],
      "buyer_role": "Purchasing manager checking a supplier comparison calculation",
      "purchase_trigger": "A pack-based amount disagrees with a total derived from the rounded item display",
      "problem": "A rounded comparison unit price is reused as the purchase amount's authoritative basis.",
      "related": [
        "guide-supplier-pack-versus-unit-price"
      ],
      "provenance": [
        {
          "label": "Python decimal: fixed-exponent quantize and rounding modes",
          "url": "https://docs.python.org/3/library/decimal.html",
          "checked": "2026-10-11",
          "claims": [
            "quantize rounds to a fixed exponent; rounding policy must be selected explicitly."
          ]
        },
        {
          "label": "W3C tabular model: units need metadata",
          "url": "https://www.w3.org/TR/tabular-data-model/",
          "checked": "2026-10-11",
          "claims": [
            "Units are not a built-in interpretation of numeric table values."
          ]
        },
        {
          "label": "Current local regression-test repair",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Explicit invented inputs",
          "body": [
            "Currency is USD; price is 19.99 per pack; each pack contains 12 items; the order quantity is three whole packs. The example rounds a displayed per-item price half-up to cents. Tax, freight, discounts, variable pack sizes and foreign exchange are excluded. This is arithmetic, not an invoice, purchase recommendation or accounting rule."
          ],
          "items": [],
          "code": "items ordered = 12 items/pack × 3 packs = 36 items\npack-based amount = USD 19.99/pack × 3 packs = USD 59.97\nunrounded item price = USD 19.99 ÷ 12 = USD 1.665833…\ndisplayed item price, half-up = USD 1.67\nwrong display-based total = USD 1.67 × 36 = USD 60.12\ndifference = USD 0.15"
        },
        {
          "heading": "The expected assertions",
          "body": [
            "Assert 36 items and 5,997 cents as separate results. Assert that the 167-cent display value is not used to derive the amount. The local synthetic model uses exact integer-cent arithmetic for these nonnegative inputs; it is not a general decimal library or an implemented supplier importer."
          ],
          "items": [
            "Unknown, zero, negative or fractional pack sizes are held under this example's whole-pack policy.",
            "Confirm whether the real supplier quotes per item, per pack or by weight before comparing.",
            "A real rounding policy must be chosen by the authorised business owner, not copied from this example."
          ]
        },
        {
          "heading": "What this evidence cannot establish",
          "body": [
            "No supplier order, application preview or payment was executed. These checks cannot establish taxes, freight, legal invoice amounts or product equivalence. The correct arithmetic still produces a misleading comparison if the source's units or currency were mapped incorrectly."
          ],
          "items": [
            "Keep quantity conversion and monetary basis visible in the acceptance request.",
            "Real documents and customer records are unnecessary for the initial reproduction."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "One existing-code calculation defect with an owner-approved unit and rounding rule may fit fix-one-bug-with-regression-test, from £295 after bounded synthetic reproduction and a fixed repair quote. Accounting policy, schema changes, landed-cost modelling and correction of real orders are not included. Send invented inputs, the stated basis and the expected results initially, not code or private financial documents. The price is untested and payment follows agreed passing checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-supplier-pack-versus-unit-price"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/supplier-pack-price-calculation/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/examples/supplier-pack-price-calculation/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Fsupplier-pack-price-calculation%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fexamples%2Fsupplier-pack-price-calculation%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "example-supplier-feed-version-disposition",
      "type": "example",
      "title": "Synthetic feed-disposition sequence: newer, late, repeated and conflicting updates",
      "description": "Starting at supplier version 41, a six-step expected-state sequence shows when a feed changes the accepted version and when the previous state must remain intact.",
      "url": "/examples/supplier-feed-version-disposition/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds"
      ],
      "buyer_role": "Operations manager specifying supplier-feed acceptance and exception behaviour",
      "purchase_trigger": "Retries or out-of-order completion overwrite a previously accepted feed",
      "problem": "The importer lacks a testable distinction between freshness, repetition, version conflict and invalid input.",
      "related": [
        "guide-supplier-feed-freshness-order",
        "guide-supplier-conflicting-duplicate-rows",
        "collection-supplier-feed-import-checks"
      ],
      "provenance": [
        {
          "label": "PostgreSQL conditional conflict update",
          "url": "https://www.postgresql.org/docs/current/sql-insert.html",
          "checked": "2026-10-11",
          "claims": [
            "ON CONFLICT DO UPDATE accepts a WHERE condition; this mechanism does not establish supplier business precedence."
          ]
        },
        {
          "label": "Current single-bug repair",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        },
        {
          "label": "Current feature-preview scope",
          "url": "https://syntheticindustry.ai/services/ship-one-feature-with-running-preview/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Declared policy and initial state",
          "body": [
            "This invented supplier issues comparable nonnegative integer versions for one fixed coverage. Initial accepted state is version 41, content A. Content letters stand for equality tokens, not timestamps or actual supplier hashes. An equal version with different content is held; a legitimate same-version correction would need a separately authorised policy."
          ],
          "items": []
        },
        {
          "heading": "Six inputs, with expected state after each",
          "body": [
            "Evaluate these inputs sequentially. Rejecting a feed must leave the accepted version and content unchanged. A conflicting duplicate inside an otherwise newer feed holds it before publication under this example's whole-feed policy."
          ],
          "items": [],
          "code": "incoming                 | expected disposition | accepted state\n42, content B            | accept               | 42, B\n41, content A arrives late| stale                | 42, B\n42, content B repeats    | no-op                | 42, B\n42, content C            | hold-version-conflict| 42, B\nunknown version, D       | hold-version         | 42, B\n43, E; conflicting rows  | hold-duplicate       | 42, B"
        },
        {
          "heading": "Duplicate rows are a separate input check",
          "body": [
            "Two Alder/00123 rows with equal price 19.99 and stock 5 receive an explicit collapse-identical disposition in the local model. If one price is 20.49 instead, either row ordering produces hold-duplicate. A Birch row with SKU 00123 is not a duplicate of Alder's row. These rules compare only the authored business fields; real feed equivalence must name every field that matters."
          ],
          "items": [
            "Source order is not precedence unless documented.",
            "The local model tests sequential decisions, not locks, transactions, retries after partial writes or concurrent workers.",
            "No database or supplier system was exercised, and no production acceptance follows."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "A deterministic defect in an existing local version-decision function may fit the regression-test repair from £295 after bounded synthetic reproduction and a fixed quote. One new version-disposition preview interaction in an existing web app may fit the feature-preview offer from £750 with its already available isolated private preview and other eligibility conditions. Atomic multi-row publication, new connectors, concurrent database tests and historical recovery need separate scope. Send invented input order and expected state, not private payloads or credentials. Prices are untested and payment follows agreed checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-supplier-conflicting-duplicate-rows",
        "guide-supplier-feed-freshness-order"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/supplier-feed-version-disposition/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/examples/supplier-feed-version-disposition/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Fsupplier-feed-version-disposition%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fexamples%2Fsupplier-feed-version-disposition%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-supplier-sku-text-identity",
      "type": "guide",
      "title": "Supplier SKUs lose leading zeros: preserve the identifier before importing",
      "description": "Keep supplier identifiers textual and compare exact keys before a stock or price feed creates a second product or updates the wrong one.",
      "url": "/guides/supplier-sku-text-identity/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds",
        "csv",
        "csv-files",
        "postgresql"
      ],
      "buyer_role": "Operations manager at a small distributor with an existing stock application",
      "purchase_trigger": "A supplier feed matches the wrong item or creates a new item after an identifier changes shape",
      "problem": "An identifier is treated as a number or normalized without the supplier's identity rule.",
      "related": [
        "example-supplier-key-collision-matrix",
        "guide-supplier-key-namespace"
      ],
      "provenance": [
        {
          "label": "Python csv documentation: reader type conversion",
          "url": "https://docs.python.org/3/library/csv.html",
          "checked": "2026-10-11",
          "claims": [
            "csv.reader returns strings by default; QUOTE_NONNUMERIC converts unquoted fields to floats."
          ]
        },
        {
          "label": "Current regression-test repair scope and proposed price",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "A product code is not a quantity",
          "body": [
            "The invented codes 00123 and 123 identify different products in this example. A supplier might instead declare them equivalent; get that rule in writing rather than assuming it. Inspect the original permitted file, parsed field and lookup key separately. Once an upstream spreadsheet has removed the zero, converting the damaged value back to text cannot recover the original code."
          ],
          "items": [
            "Keep leading zeros, letter case and surrounding-space policy explicit.",
            "Include a long all-digit code and an alphanumeric code in the synthetic fixture.",
            "Do not open and resave the only copy merely to inspect it."
          ]
        },
        {
          "heading": "Check conversions at the import boundary",
          "body": [
            "Python's CSV reader defaults to strings, but QUOTE_NONNUMERIC converts unquoted fields to floats. A different parser or spreadsheet can follow different rules. Inspect the installed importer rather than assuming every CSV reader is safe. Numeric conversion, trimming and case folding are separate decisions; a string field can still be altered by later normalization."
          ],
          "items": [
            "Compare exact synthetic strings after parsing, mapping and lookup.",
            "Do not infer identity from how a spreadsheet displays a cell.",
            "Unknown or already damaged identifiers need an exception, not a guessed zero-padding rule."
          ]
        },
        {
          "heading": "What a repair must demonstrate",
          "body": [
            "Use 00123, 123 and an invented long identifier. The same fixture must reach three distinct intended keys without numeric coercion. Capture the failure on the old code and the pass after repair. Check a known ordinary code as well. This batch supplies an authored collision matrix, not a production import or customer correction."
          ],
          "items": [
            "Historical duplicates or wrong-product updates require separately authorised reconciliation.",
            "A safe local parser test does not prove supplier downloads or live database writes work."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "One reproducible local identifier-conversion bug may fit fix-one-bug-with-regression-test, from £295 after bounded reproduction and a fixed repair quote. The code must run in isolation with synthetic inputs and no production credentials. Existing-record repair, supplier onboarding, a schema migration or a live feed connection is outside that offer. Send invented input strings and expected keys, not source code, customer records or access invitations. The price is an untested proposal; payment follows agreed passing checks and sign-off."
          ],
          "items": [
            "If the original identifier has already been lost, ask the supplier or authorised operator for the authoritative source before requesting a code repair."
          ]
        }
      ],
      "incoming": [
        "platform-csv-files",
        "example-supplier-key-collision-matrix",
        "guide-supplier-key-namespace",
        "collection-supplier-feed-import-checks"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/supplier-sku-text-identity/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/supplier-sku-text-identity/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fsupplier-sku-text-identity%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fsupplier-sku-text-identity%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-supplier-key-namespace",
      "type": "guide",
      "title": "Two suppliers use the same SKU: match the supplier and code together",
      "description": "Prevent one supplier's stock or price from landing on another supplier's item, and keep unapproved cross-supplier mappings out of an automatic update.",
      "url": "/guides/supplier-key-namespace/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds",
        "postgresql"
      ],
      "buyer_role": "Purchasing or operations manager maintaining several supplier catalogues",
      "purchase_trigger": "A feed overwrites a different supplier's item with an identical local SKU",
      "problem": "A supplier-local code is used as a globally unique lookup or an unapproved product mapping.",
      "related": [
        "guide-supplier-sku-text-identity",
        "example-supplier-key-collision-matrix"
      ],
      "provenance": [
        {
          "label": "PostgreSQL constraints: multicolumn uniqueness, primary and foreign keys",
          "url": "https://www.postgresql.org/docs/current/ddl-constraints.html",
          "checked": "2026-10-11",
          "claims": [
            "A composite unique constraint applies to the combination, not each column individually.",
            "Primary-key columns are non-null.",
            "A foreign key enforces a reference, not a business judgement that two items are equivalent."
          ]
        },
        {
          "label": "Existing repair offer",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        },
        {
          "label": "Existing feature-preview offer",
          "url": "https://syntheticindustry.ai/services/ship-one-feature-with-running-preview/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Separate source identity from your internal product",
          "body": [
            "Supplier Alder's 00123 and supplier Birch's 00123 are separate source keys in this synthetic case. Neither their equal code nor a similar description establishes that they sell the same item. Keep a supplier identifier beside the exact local SKU, then use an explicitly approved mapping to any internal product."
          ],
          "items": [
            "Require both parts of the source key before matching.",
            "Do not auto-map on a fuzzy product name.",
            "An unknown source key should remain unassigned until the purchasing owner approves its mapping."
          ]
        },
        {
          "heading": "A constraint protects the rule you choose",
          "body": [
            "PostgreSQL supports a composite unique constraint or primary key. A unique constraint alone can permit null-containing keys by default, so missing supplier or SKU needs its own validation. A foreign key can keep a mapping attached to an existing row, but cannot prove that the purchasing owner chose the correct physical product. Inspect constraints and application lookup logic separately."
          ],
          "items": [
            "Two independent supplier and SKU references do not establish the intended supplier-SKU pair.",
            "Do not change a live key or add a constraint before checking historical collisions."
          ]
        },
        {
          "heading": "Acceptance includes a collision and an unknown",
          "body": [
            "Give two invented suppliers the same SKU but different internal products and stock quantities. Updating Alder must leave Birch unchanged. A third unknown source key must enter the agreed exception path, not silently create or map a product. Keep the expected key-to-product mapping beside the result."
          ],
          "items": [
            "The supplied key matrix is an authored specification; no database migration or supplier matching has been performed.",
            "A product description or equal record count is not acceptance evidence."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "A wrong lookup in existing code may fit the synthetic-data bug repair, from £295 after bounded reproduction and a fixed quote. One new exception-review interaction in an existing web app may fit the feature-preview offer, from £750, only with an existing isolated private preview and no payment or personal-data changes. Building a product-master system, cleaning real mappings or migrating database keys needs separate scope. Send the invented collision and desired result initially; do not send live supplier files, code or credentials. Prices are untested proposals; work and payment require the relevant agreement and sign-off."
          ],
          "items": [
            "If nobody can authorise the mapping policy, purchasing ownership must be resolved before automation."
          ]
        }
      ],
      "incoming": [
        "example-supplier-key-collision-matrix",
        "guide-supplier-sku-text-identity",
        "guide-supplier-conflicting-duplicate-rows",
        "collection-supplier-feed-import-checks"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/supplier-key-namespace/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/supplier-key-namespace/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fsupplier-key-namespace%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fsupplier-key-namespace%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-supplier-conflicting-duplicate-rows",
      "type": "guide",
      "title": "A supplier feed repeats one key with different prices: reject the conflict before updating",
      "description": "Distinguish an identical duplicate from conflicting rows and choose a documented disposition instead of allowing file order to decide a business value.",
      "url": "/guides/supplier-conflicting-duplicate-rows/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds",
        "postgresql"
      ],
      "buyer_role": "Purchasing manager responsible for supplier price-feed exceptions",
      "purchase_trigger": "The same supplier-SKU appears twice with disagreeing stock or price values",
      "problem": "Multiple source rows compete for one target key without an explicit conflict policy.",
      "related": [
        "guide-supplier-key-namespace",
        "example-supplier-feed-version-disposition"
      ],
      "provenance": [
        {
          "label": "PostgreSQL INSERT: ON CONFLICT cardinality and conditional update",
          "url": "https://www.postgresql.org/docs/current/sql-insert.html",
          "checked": "2026-10-11",
          "claims": [
            "ON CONFLICT DO UPDATE cannot affect one existing row more than once within the command."
          ]
        },
        {
          "label": "PostgreSQL UPDATE: multiple FROM matches",
          "url": "https://www.postgresql.org/docs/current/sql-update.html",
          "checked": "2026-10-11",
          "claims": [
            "When a target row joins multiple source rows, which row supplies the update is not readily predictable."
          ]
        },
        {
          "label": "Existing single-bug scope",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Group before applying",
          "body": [
            "Group rows by the agreed supplier-plus-SKU key. In this example, an exact duplicate of the agreed business fields can be reported and collapsed, while any price or quantity disagreement holds the entire feed for review. That is an authored policy, not a universal supplier rule. Row position alone is not a credible effective date."
          ],
          "items": [
            "Define which fields make two rows equivalent.",
            "Keep conflicting synthetic values and the source row numbers in the exception report.",
            "Do not silently use the first or last row unless that precedence is part of the source contract."
          ]
        },
        {
          "heading": "Upsert is not conflict adjudication",
          "body": [
            "PostgreSQL documents a cardinality violation if one ON CONFLICT DO UPDATE command affects the same existing row more than once. UPDATE FROM has another trap: multiple matching source rows can produce an unpredictable chosen update. Neither statement decides which price the supplier intended. Validate the source group before a write and record its disposition."
          ],
          "items": [
            "A unique target key does not itself validate duplicate input rows.",
            "Do not weaken constraints to make a problematic batch pass."
          ]
        },
        {
          "heading": "Test independence from file order",
          "body": [
            "Use two equal synthetic rows, then two rows with the same key and different prices. Reversing their order must not turn a held conflict into a successful update. The example disposition matrix holds conflicting batches before any target change; it does not replay or repair historical imports."
          ],
          "items": [
            "Check the exception identifies the conflicting key and values without exposing private payloads.",
            "Document whether an identical duplicate is a warning or a rejection in the buyer's actual policy."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "One existing, deterministic duplicate-selection defect may fit the local regression-test repair, from £295 after bounded reproduction and a fixed quote. A new feed-validation workflow or broad database redesign is not automatically a bug repair. If the conflict policy is undecided, the purchasing owner must settle it first. Initial inputs are invented duplicate rows, the expected disposition and the application stack, not a real price list or database credentials. Production reconciliation and deployment are excluded; the proposed price is untested and payment follows agreed checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "example-supplier-feed-version-disposition",
        "guide-supplier-feed-freshness-order",
        "collection-supplier-feed-import-checks"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/supplier-conflicting-duplicate-rows/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/supplier-conflicting-duplicate-rows/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fsupplier-conflicting-duplicate-rows%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fsupplier-conflicting-duplicate-rows%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-supplier-blank-price-update",
      "type": "guide",
      "title": "Blank supplier price clears a good value: distinguish unchanged, empty and explicit removal",
      "description": "Give missing fields and blank cells different update meanings before a partial supplier feed erases a price or silently substitutes zero.",
      "url": "/guides/supplier-blank-price-update/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds",
        "csv",
        "postgresql"
      ],
      "buyer_role": "Purchasing manager whose application accepts partial supplier updates",
      "purchase_trigger": "A partial feed unexpectedly removes a stored price or replaces it with zero",
      "problem": "Parser absence, an empty value and an explicit clear request collapse into the same update.",
      "related": [
        "example-supplier-update-presence-contract",
        "guide-supplier-feed-header-drift",
        "guide-supplier-snapshot-versus-delta"
      ],
      "provenance": [
        {
          "label": "Python DictReader and CSV writer missing-value behaviour",
          "url": "https://docs.python.org/3/library/csv.html",
          "checked": "2026-10-11",
          "claims": [
            "DictReader can fill missing fields with restval, default None.",
            "The CSV writer writes None as an empty string, a non-reversible conversion."
          ]
        },
        {
          "label": "PostgreSQL UPDATE assignment semantics",
          "url": "https://www.postgresql.org/docs/current/sql-update.html",
          "checked": "2026-10-11",
          "claims": [
            "Columns omitted from SET retain their existing values."
          ]
        },
        {
          "label": "Existing regression-test repair",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Write a presence contract",
          "body": [
            "For the worked example, an intentionally omitted optional price field means unchanged, a present blank price is an exception, numeric zero is a submitted value requiring the declared zero-price policy, and removal requires a separate explicit operation. Your supplier may specify different meanings. Get those meanings approved rather than treating every falsy value as missing."
          ],
          "items": [
            "Distinguish a deliberately absent column from a row shorter than the declared header.",
            "Do not substitute zero to make a missing required price parse.",
            "A clear-price operation must be permitted explicitly; it is not implied by a blank cell."
          ]
        },
        {
          "heading": "Parsing does not preserve every distinction",
          "body": [
            "Python DictReader fills short rows with a configurable restval, defaulting to None. Its writer can convert None to an empty string, losing the distinction on a round trip. A malformed short row is therefore not evidence of an intentional no-change instruction. PostgreSQL preserves columns omitted from SET; assigning NULL is a different action and remains subject to constraints."
          ],
          "items": [
            "Validate row width before interpreting business fields.",
            "Keep field presence separate from its parsed value.",
            "Do not assume quoting an empty CSV field defines a clear instruction."
          ]
        },
        {
          "heading": "Acceptance inspects the previous value",
          "body": [
            "Start with an invented stored price of 12.50. The deliberately omitted-price case must retain 12.50; a present blank must report an exception and retain it under this example policy. A present zero and an explicit removal are separate cases, not variations of absence. Inspect resulting value and disposition, not just an imported-row count."
          ],
          "items": [
            "No real prices were changed; the supplied matrix is synthetic.",
            "Historical data loss requires separate recovery evidence and authorised reconciliation."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "A deterministic existing-code mistake in presence handling may fit fix-one-bug-with-regression-test, from £295 after bounded synthetic reproduction and a fixed quote. Policy invention, correcting real price lists, tax advice and schema migration are outside that repair. Send the synthetic prior value, submitted field state and expected disposition, not client files or source code. If the supplier cannot define blank semantics, hold automatic updates and ask its authorised operator; do not guess. Price is an untested proposal and payment follows agreed passing checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "example-supplier-update-presence-contract",
        "guide-supplier-feed-header-drift",
        "collection-supplier-feed-import-checks"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/supplier-blank-price-update/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/supplier-blank-price-update/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fsupplier-blank-price-update%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fsupplier-blank-price-update%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-supplier-snapshot-versus-delta",
      "type": "guide",
      "title": "An item disappears from a supplier feed: is it a full snapshot or just a delta?",
      "description": "Do not turn an omitted SKU into zero stock or discontinued status until the source defines completeness, coverage and deletion semantics.",
      "url": "/guides/supplier-snapshot-versus-delta/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds"
      ],
      "buyer_role": "Stock-control manager consuming supplier availability updates",
      "purchase_trigger": "Products vanish or become unavailable after a smaller-than-usual feed",
      "problem": "Absence in a partial update is mistaken for an authoritative stock or discontinuation statement.",
      "related": [
        "example-supplier-update-presence-contract",
        "guide-supplier-feed-freshness-order"
      ],
      "provenance": [
        {
          "label": "W3C tabular data model: tables, cells and metadata",
          "url": "https://www.w3.org/TR/tabular-data-model/",
          "checked": "2026-10-11",
          "claims": [
            "The tabular model describes rows, cells, keys and metadata; those structural descriptions do not establish a supplier's full-snapshot or delta contract."
          ]
        },
        {
          "label": "Existing one-feature preview scope",
          "url": "https://syntheticindustry.ai/services/ship-one-feature-with-running-preview/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "A parseable file can still be incomplete",
          "body": [
            "A CSV with valid rows does not say whether it covers all products, one warehouse, a filtered selection or only changes since an earlier feed. This is an operational inference, not a promise from the W3C tabular standard. Ask the source owner for the feed type, coverage and completion signal before interpreting an omitted SKU."
          ],
          "items": [
            "Record supplier, warehouse or catalogue boundary and source-issued version.",
            "Distinguish zero availability from discontinuation; neither is implied by absence alone.",
            "A successful download or plausible row count cannot prove source completeness."
          ]
        },
        {
          "heading": "Define absence at the coverage boundary",
          "body": [
            "In the synthetic delta example, an omitted item is unchanged. In the complete-snapshot example, an omitted item within the explicitly covered set is marked unavailable under an owner-approved rule, not deleted or declared discontinued. If coverage or completion is unknown, the feed is held and the old state remains. These are example policies, not instructions for any named supplier."
          ],
          "items": [
            "Apply absence rules only inside the declared coverage, never the whole catalogue.",
            "Keep explicit discontinuation a separate source operation.",
            "Do not infer a complete snapshot from a filename such as full.csv."
          ]
        },
        {
          "heading": "Make preview changes inspectable",
          "body": [
            "An acceptance fixture has two existing invented items and an incoming update containing only one. The preview must show different results for delta, confirmed-complete snapshot and unknown-completeness cases. It must also show that an item outside coverage is untouched. The feed's mode and source evidence should be visible alongside the proposed changes."
          ],
          "items": [
            "Hold rather than silently apply an unknown mode.",
            "A confirmation screen does not authorise a live import.",
            "This batch provides expected dispositions, not a running supplier connector."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "One feed-change preview or exception interaction in an existing internal web app can be discussed under ship-one-feature-with-running-preview, from £750 after agreeing criteria, an existing private isolated preview and two revision rounds. The offered feature must avoid payment or personal-data changes and use synthetic feed inputs without new accounts or paid services. Supplier retrieval, live stock publication, a new inventory system and historical correction need separate scope. Send invented before/after records and the approved coverage policy initially; the price is untested and payment follows passing checks and buyer sign-off."
          ],
          "items": [
            "If completeness cannot be established, keep the source updates under the existing authorised operator's review rather than making absence destructive."
          ]
        }
      ],
      "incoming": [
        "example-supplier-update-presence-contract",
        "guide-supplier-blank-price-update",
        "guide-supplier-feed-freshness-order",
        "collection-supplier-feed-import-checks"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/supplier-snapshot-versus-delta/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/supplier-snapshot-versus-delta/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fsupplier-snapshot-versus-delta%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fsupplier-snapshot-versus-delta%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-supplier-pack-versus-unit-price",
      "type": "guide",
      "title": "Supplier quotes per pack, your app compares per item: make the units explicit",
      "description": "Keep pack size, stock units and price basis separate so an apparently cheaper supplier is not selected using incomparable values or rounded display prices.",
      "url": "/guides/supplier-pack-versus-unit-price/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds"
      ],
      "buyer_role": "Purchasing manager comparing supplier pack offers in an existing application",
      "purchase_trigger": "A price comparison or stock calculation treats one carton as one individual item",
      "problem": "A numeric value is accepted without its purchase unit, pack size or price basis.",
      "related": [
        "example-supplier-pack-price-calculation"
      ],
      "provenance": [
        {
          "label": "W3C tabular model: units metadata",
          "url": "https://www.w3.org/TR/tabular-data-model/",
          "checked": "2026-10-11",
          "claims": [
            "Units are not a built-in part of the tabular model and can be expressed through metadata."
          ]
        },
        {
          "label": "Python decimal: exact decimal inputs and explicit rounding",
          "url": "https://docs.python.org/3/library/decimal.html",
          "checked": "2026-10-11",
          "claims": [
            "Constructing Decimal from a float preserves the float's exact value, rather than recovering the originally intended decimal.",
            "quantize rounds to a fixed exponent with the selected rounding policy."
          ]
        },
        {
          "label": "Existing repair offer",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        },
        {
          "label": "Existing preview feature offer",
          "url": "https://syntheticindustry.ai/services/ship-one-feature-with-running-preview/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Name the denominator",
          "body": [
            "Write price currency, price per pack or per item, items per pack and the unit of the stock quantity. A source quantity of 5 could mean five packs or five items. Do not infer units from a description, a small price or a familiar product. The W3C tabular model explicitly treats units as metadata rather than automatically interpreting every number."
          ],
          "items": [
            "Hold rows with unknown pack size or price basis.",
            "Keep pack sizes positive whole numbers only where that matches the actual product rule.",
            "Weight-based goods, variable packs and currency conversion need a different contract."
          ]
        },
        {
          "heading": "Comparison price is not the payable amount",
          "body": [
            "The worked example is USD 19.99 per pack of 12, ordering three packs. That means 36 items and a pack-based amount of USD 59.97. A displayed per-item value rounded half-up to two decimals is USD 1.67; multiplying that display by 36 gives USD 60.12, not the pack-based amount. The example's rounding policy is explicit and is not tax or accounting advice."
          ],
          "items": [
            "Calculate the contractual amount from its actual price basis.",
            "Keep sufficient intermediate precision and round at the owner-approved boundary.",
            "Decimal arithmetic does not decide the unit, tax, freight or rounding policy for you."
          ]
        },
        {
          "heading": "Acceptance checks dimensions and amounts",
          "body": [
            "Use an invented pack offer and assert both item quantity and pack-based amount. Include a missing pack size and a zero pack size; under this example policy both are exceptions. Compare a whole-item offer only after confirming compatible currency and units. The provided arithmetic is synthetic and excludes tax, freight, discounts and purchase-order submission."
          ],
          "items": [
            "A neatly formatted two-decimal display is not evidence that the calculation used the right basis.",
            "No supplier order or invoice was created."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "One existing-code unit-conversion defect may fit the synthetic regression-test repair, from £295 after bounded reproduction and a fixed quote. One new unit-aware comparison interaction may fit the existing web-app feature-preview offer, from £750, if its isolated private preview and other eligibility conditions already hold. Tax policy, landed-cost modelling, payments, accounting changes and real purchasing actions are excluded. Send invented pack price, size, quantity and expected result initially; prices are untested and payment follows agreed checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "example-supplier-pack-price-calculation",
        "collection-supplier-feed-import-checks"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/supplier-pack-versus-unit-price/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/supplier-pack-versus-unit-price/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fsupplier-pack-versus-unit-price%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fsupplier-pack-versus-unit-price%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-supplier-feed-freshness-order",
      "type": "guide",
      "title": "Yesterday's supplier feed finishes last: keep older data from replacing a newer version",
      "description": "Compare source-issued versions at the publication boundary and distinguish a late old feed from an authorised correction to the current one.",
      "url": "/guides/supplier-feed-freshness-order/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds",
        "postgresql"
      ],
      "buyer_role": "Operations manager whose supplier-feed imports overlap or retry",
      "purchase_trigger": "Stock or prices revert when a delayed earlier import completes",
      "problem": "Completion or arrival order is treated as source freshness and an older feed replaces accepted newer data.",
      "related": [
        "example-supplier-feed-version-disposition",
        "guide-supplier-snapshot-versus-delta",
        "guide-supplier-conflicting-duplicate-rows"
      ],
      "provenance": [
        {
          "label": "PostgreSQL INSERT: conditional ON CONFLICT update",
          "url": "https://www.postgresql.org/docs/current/sql-insert.html",
          "checked": "2026-10-11",
          "claims": [
            "ON CONFLICT DO UPDATE can apply a WHERE condition after detecting the conflict.",
            "Conflicting rows may be locked even when the condition prevents their update."
          ]
        },
        {
          "label": "Existing repair scope",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        },
        {
          "label": "Existing feature-preview scope",
          "url": "https://syntheticindustry.ai/services/ship-one-feature-with-running-preview/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Use source ordering, not download time",
          "body": [
            "In the authored example, supplier versions increase from 41 to 42. A delayed version 41 is stale after 42 has been accepted even if 41 finishes later. This rule requires a trustworthy source-issued ordering contract within the same supplier and coverage. A timestamp in a local filename, a hash or a download completion time does not establish that contract."
          ],
          "items": [
            "A hash can identify content equality; it is not an age ordering.",
            "Equal version with different content is a conflict under this example policy.",
            "If the source has no comparable version, hold ambiguous publication for the authorised operator instead of guessing."
          ]
        },
        {
          "heading": "The gate and the changes must agree",
          "body": [
            "PostgreSQL permits a conditional ON CONFLICT update, but a row-level condition alone does not make a multi-row supplier snapshot safe. The authoritative version check, all covered stock/price changes and recorded acceptance must share the agreed publication boundary. This is an engineering requirement to be designed and reviewed, not a SQL recipe to paste into production."
          ],
          "items": [
            "Recheck freshness at publication, not only when the file is fetched.",
            "Do not update child rows after a rejected version gate.",
            "An authorised correction with the same version needs an explicit correction policy, not a silent exception."
          ]
        },
        {
          "heading": "Acceptance includes reversed completion",
          "body": [
            "The synthetic contract accepts 42 after 41, then rejects the late 41 without changing any values. Repeating 42 with identical content is a no-op; repeating 42 with different content is held. An unknown source version is also held. The local example tests these decisions only; it does not execute concurrent transactions or prove a database publication design."
          ],
          "items": [
            "Inspect unchanged state after every rejected or repeated feed.",
            "A passing sequential fixture is not a concurrency or recovery test."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "A local deterministic freshness-decision bug may fit fix-one-bug-with-regression-test, from £295 after bounded synthetic reproduction and a fixed quote. A single preview interaction showing accepted, stale and conflicting versions may fit ship-one-feature-with-running-preview, from £750 with its existing safe preview conditions. A new atomic publication architecture, live concurrency test, feed connector or database/data migration needs separate scope; neither starting price buys that project. Send invented versions and expected dispositions, not private feed payloads, code or credentials. Prices are untested and payment follows agreed checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "example-supplier-feed-version-disposition",
        "guide-supplier-snapshot-versus-delta",
        "collection-supplier-feed-import-checks"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/supplier-feed-freshness-order/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/supplier-feed-freshness-order/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fsupplier-feed-freshness-order%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fsupplier-feed-freshness-order%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "guide-supplier-feed-header-drift",
      "type": "guide",
      "title": "Supplier adds a CSV column: reject header drift before fields shift into the wrong place",
      "description": "Validate the declared header and every row's shape before mapping a supplier stock or price update, rather than accepting a successfully parsed but misaligned record.",
      "url": "/guides/supplier-feed-header-drift/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds",
        "csv",
        "csv-files",
        "postgresql"
      ],
      "buyer_role": "Operations manager responsible for an existing supplier CSV import",
      "purchase_trigger": "The supplier changes a feed layout and values appear under the wrong business fields",
      "problem": "Positional assumptions, undeclared headers or short rows are accepted as a valid supplier schema.",
      "related": [
        "guide-supplier-blank-price-update",
        "collection-supplier-feed-import-checks"
      ],
      "provenance": [
        {
          "label": "Python csv: DictReader, dialects and header detection",
          "url": "https://docs.python.org/3/library/csv.html",
          "checked": "2026-10-11",
          "claims": [
            "DictReader uses the first row as field names unless fieldnames is supplied.",
            "Extra row fields use restkey and short-row fields use restval.",
            "Sniffer.has_header is a rough heuristic that can give false positives and false negatives."
          ]
        },
        {
          "label": "Existing bug-repair scope",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Treat the feed layout as a contract",
          "body": [
            "Write the expected delimiter, encoding, required header names, allowed optional columns and column-order policy. Decide whether a renamed, duplicate or unknown column rejects the feed or requires a new mapping version. A parser accepting bytes does not establish that stock and price reached the intended fields."
          ],
          "items": [
            "Inspect duplicate header names before building a name-to-value object.",
            "Do not auto-accept a new unit or currency column as an unrelated extra.",
            "A supplier format change needs an approved mapping, not a guess from sample values."
          ]
        },
        {
          "heading": "Short rows are not intentional partial updates",
          "body": [
            "Python DictReader documents restval for missing fields and restkey for surplus fields. Check both rather than dropping extras or allowing defaults to erase prices. Header detection is heuristic; an apparent first row is not a substitute for the source's declared layout. CSV records can contain quoted newlines, so physical line count is not record count."
          ],
          "items": [
            "A deliberately omitted optional column is different from a row with too few fields.",
            "Use a proper CSV parser; splitting on commas does not handle quoted data.",
            "The documentation does not specify duplicate-header preservation; reject duplicates under an explicit importer policy."
          ]
        },
        {
          "heading": "Acceptance uses a changed layout",
          "body": [
            "Create synthetic files with reordered declared columns, one unknown column, a duplicate header, a short row and a quoted comma. Assert correct mapping or the specific agreed rejection before any application update. Keep these input cases in the regression; a test containing only the old supplier layout cannot establish the fix."
          ],
          "items": [
            "This guide proposes checks; the supplied local example fixtures do not execute a CSV parser.",
            "Compare parsed fields and rejection reasons, not just the number of accepted rows."
          ]
        },
        {
          "heading": "Priced enquiry and non-fit",
          "body": [
            "One existing-code header or row-shape defect may fit the local regression-test repair, from £295 after bounded reproduction and a fixed quote. Supplier-format negotiation, a new universal importer, production data correction and a live feed connection are excluded. Send invented headers, one synthetic row and the intended mapping initially, never real price lists, source code or access keys. If the source layout is undocumented, establish it with the existing authorised source owner before automating. The price is untested; payment follows agreed passing checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-mapping-supplier-category-unmapped-queue",
        "platform-csv-files",
        "guide-supplier-blank-price-update",
        "collection-supplier-feed-import-checks"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/supplier-feed-header-drift/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/guides/supplier-feed-header-drift/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fsupplier-feed-header-drift%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fguides%2Fsupplier-feed-header-drift%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    },
    {
      "id": "collection-supplier-feed-import-checks",
      "type": "category",
      "title": "Supplier stock and price import checks: choose the first failing boundary",
      "description": "A distributor-focused sequence from CSV shape through identity, field meaning, units and feed publication, linked to worked synthetic cases and narrowly eligible paid enquiries.",
      "url": "/collections/supplier-feed-import-checks/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds",
        "postgresql"
      ],
      "buyer_role": "Operations owner triaging a supplier feed before requesting an application change",
      "purchase_trigger": "An import succeeds technically but the resulting product, price or stock state is wrong",
      "problem": "The buyer needs to locate the first broken contract instead of collecting unrelated fixes or replaying a live file.",
      "related": [
        "guide-supplier-feed-header-drift",
        "guide-supplier-sku-text-identity",
        "guide-supplier-key-namespace",
        "guide-supplier-conflicting-duplicate-rows",
        "guide-supplier-blank-price-update",
        "guide-supplier-pack-versus-unit-price",
        "guide-supplier-snapshot-versus-delta",
        "guide-supplier-feed-freshness-order"
      ],
      "provenance": [
        {
          "label": "Python CSV: fields, dialects and heuristic header detection",
          "url": "https://docs.python.org/3/library/csv.html",
          "checked": "2026-10-11",
          "claims": [
            "Parsing and header detection have explicit type and missing-field behaviours; successful parsing does not establish supplier business meaning."
          ]
        },
        {
          "label": "PostgreSQL constraints and key rules",
          "url": "https://www.postgresql.org/docs/current/ddl-constraints.html",
          "checked": "2026-10-11",
          "claims": [
            "Key and reference constraints protect a declared data model, not all business interpretation."
          ]
        },
        {
          "label": "Existing regression-test repair",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        },
        {
          "label": "Existing one-feature preview",
          "url": "https://syntheticindustry.ai/services/ship-one-feature-with-running-preview/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "1. Establish shape and identity",
          "body": [
            "Start with invented rows, not a live replay. Confirm the declared header and row width, then exact text identifiers, supplier namespace and approved mapping. If these fail, later price or quantity checks can be attached to the wrong product. The related key matrix demonstrates leading-zero and cross-supplier collisions."
          ],
          "items": [
            "Header drift: inspect duplicate, renamed, unknown or missing columns.",
            "Identifier conversion: compare the original string and lookup key.",
            "Namespace collision: compare supplier-plus-code pairs and unmapped exceptions."
          ]
        },
        {
          "heading": "2. Establish each field's meaning",
          "body": [
            "Group duplicate keys before choosing values. Agree whether an omitted optional price is unchanged, whether blank is invalid and whether clearing requires an explicit operation. Check purchase units, pack size and the price basis before comparing suppliers. Use the presence and pack-price examples to write expected results."
          ],
          "items": [
            "A conflict is not solved merely because an upsert runs.",
            "A missing price is not automatically zero.",
            "A rounded per-item display is not automatically the purchase amount."
          ]
        },
        {
          "heading": "3. Establish feed-wide acceptance",
          "body": [
            "Confirm full versus delta mode, exact coverage and completion evidence before interpreting absent products. Compare trustworthy source versions at the publication boundary, not by local arrival time. Hold ambiguous versions or conflicts without modifying the agreed prior state. These checks do not prove atomic multi-row publication; that larger design needs separate review."
          ],
          "items": [
            "Use the version-disposition example for newer, stale, repeat and conflict cases.",
            "Do not mark the whole catalogue unavailable because one source file is small.",
            "Keep production actions and historical recovery out of diagnosis."
          ]
        },
        {
          "heading": "A narrow priced route, not an importer bundle",
          "body": [
            "One eligible local reproducible bug starts from £295 under the existing regression-test offer, after bounded reproduction and a fixed quote. One eligible new interaction in an existing web app starts from £750 under the private feature-preview offer, with its already available isolated preview, written criteria and two revision rounds. The collection is not a priced package and does not add those prices into a promise to rebuild an importer. Production credentials, real data repair, new accounts, payments and live publication remain out of these small scopes. Send invented cases and the desired result initially; prices are untested and payment follows agreed checks and sign-off."
          ],
          "items": [
            "This sequence is a commercial and engineering inference from the cited technical behaviours, not evidence that distributors have requested or paid SI for it."
          ]
        }
      ],
      "incoming": [
        "example-supplier-key-collision-matrix",
        "example-supplier-update-presence-contract",
        "example-supplier-feed-version-disposition",
        "guide-supplier-feed-header-drift"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://store-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/collections/supplier-feed-import-checks/",
          "website": ""
        },
        "idempotency_key": "UUID v4; reuse unchanged answers on retry",
        "receipt": "Durable receipt; server email delivery may be pending. Not an order.",
        "fallback": "Email with SI-* headers",
        "to": "hello@syntheticindustry.ai",
        "headers": {
          "SI-Outcome": "custom-outcome",
          "SI-Mode": "general",
          "SI-Page": "https://store-ops.syntheticindustry.ai/collections/supplier-feed-import-checks/",
          "SI-Ref": "unknown"
        },
        "url": "https://store-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fcollections%2Fsupplier-feed-import-checks%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=custom-outcome&body=SI-Outcome%3A%20custom-outcome%0ASI-Mode%3A%20general%0ASI-Page%3A%20https%3A%2F%2Fstore-ops.syntheticindustry.ai%2Fcollections%2Fsupplier-feed-import-checks%2F%0ASI-Ref%3A%20unknown%0A%0AName%3A%0ACompany%3A%0AWhat%20you%20need%3A%0ASoftware%20or%20systems%3A%0AContext%20link%20(optional)%3A%0AContact%20email%3A%0A%0APlease%20leave%20out%20passwords%2C%20keys%2C%20recovery%20links%2C%20confidential%20code%20and%20customer%20data.",
        "stored": "Website POST saves a durable first-party receipt; the host records it in the ledger and sends email. Success means saved, not delivery or acceptance."
      }
    }
  ]
}
