{
  "schema": "si-demand-engine/1",
  "site_id": "data-ops",
  "origin": "https://data-ops.syntheticindustry.ai",
  "records": [
    {
      "id": "invoice-retry-creates-duplicate-invoices",
      "type": "outcome",
      "title": "Stop a retried automation from creating a second invoice in Xero or QuickBooks Online",
      "description": "Replaying, retrying or double-running one named invoice automation leaves exactly one invoice per source order in a test accounting file, and an unknown outcome is held for a person.",
      "url": "/services/invoice-retry-creates-duplicate-invoices/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "xero",
        "quickbooks-online"
      ],
      "related": [
        "zapier-sheets-to-xero-missing-columns"
      ],
      "provenance": [
        {
          "label": "Xero documents an Idempotency-Key header on create requests, with keys kept for a short stated period and re-use with a different request rejected; its limits are quoted in the job rather than assumed.",
          "url": "https://developer.xero.com/documentation/guides/idempotent-requests/idempotency/"
        },
        {
          "label": "Intuit documents a request id on QuickBooks Online create calls that returns the original response on a repeat; the retention period is not published, so the job does not depend on it.",
          "url": "https://help.developer.intuit.com/s/article/What-is-RequestId-and-its-usage"
        },
        {
          "label": "Xero publishes a demo company that can be used for testing and that cannot send invoices.",
          "url": "https://central.xero.com/s/article/Use-the-demo-company"
        }
      ],
      "incoming": [
        "xero-contact-duplicates-from-sync",
        "platform-xero",
        "buyer-ledger-sync-operations-lead-integration-health",
        "collection-ledger-sync-restore-diagnosis-order"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "invoice-retry-creates-duplicate-invoices",
          "source": "/services/invoice-retry-creates-duplicate-invoices/",
          "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": "invoice-retry-creates-duplicate-invoices",
          "SI-Mode": "request",
          "SI-Page": "https://data-ops.syntheticindustry.ai/services/invoice-retry-creates-duplicate-invoices/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=invoice-retry-creates-duplicate-invoices&source=%2Fservices%2Finvoice-retry-creates-duplicate-invoices%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=invoice-retry-creates-duplicate-invoices&body=SI-Outcome%3A%20invoice-retry-creates-duplicate-invoices%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fdata-ops.syntheticindustry.ai%2Fservices%2Finvoice-retry-creates-duplicate-invoices%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://data-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://data-ops.syntheticindustry.ai/services/mapping-supplier-categories-to-store-categories/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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": "payout-stripe-deposit-matches-bank-line",
      "type": "outcome",
      "title": "Make every Stripe payout match one bank deposit line in Xero or QuickBooks Online",
      "description": "Each automatic Stripe payout in an agreed test period becomes one ledger entry equal to the bank deposit, with its gross, fees and refunds explained and a clearing balance that returns to zero.",
      "url": "/services/payout-stripe-deposit-matches-bank-line/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "stripe",
        "xero",
        "quickbooks-online"
      ],
      "related": [],
      "provenance": [
        {
          "label": "Stripe documents that automatic payouts can combine many transactions, that balance transactions can be listed for one payout, and that manual payouts cannot be tied to specific transactions.",
          "url": "https://docs.stripe.com/payouts/reconciliation"
        },
        {
          "label": "Stripe's payout reconciliation report groups each automatic payout by reporting category, groups by estimated arrival date rather than bank posting date, and its data can lag the payout.",
          "url": "https://docs.stripe.com/reports/payout-reconciliation"
        }
      ],
      "incoming": [
        "example-recon-stripe-payout-composition",
        "buyer-recon-bookkeeper-payments-to-ledger",
        "collection-recon-payment-to-ledger-diagnosis-order"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "payout-stripe-deposit-matches-bank-line",
          "source": "/services/payout-stripe-deposit-matches-bank-line/",
          "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": "payout-stripe-deposit-matches-bank-line",
          "SI-Mode": "request",
          "SI-Page": "https://data-ops.syntheticindustry.ai/services/payout-stripe-deposit-matches-bank-line/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=payout-stripe-deposit-matches-bank-line&source=%2Fservices%2Fpayout-stripe-deposit-matches-bank-line%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=payout-stripe-deposit-matches-bank-line&body=SI-Outcome%3A%20payout-stripe-deposit-matches-bank-line%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fdata-ops.syntheticindustry.ai%2Fservices%2Fpayout-stripe-deposit-matches-bank-line%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": "xero-contact-duplicates-from-sync",
      "type": "outcome",
      "title": "Make a customer sync reuse the right Xero contact instead of creating near-duplicates",
      "description": "Replaying a synthetic customer list through one named sync creates each customer once in a Xero demo organisation, and a changed email or name updates the same contact.",
      "url": "/services/xero-contact-duplicates-from-sync/",
      "updated": "2026-10-11",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "xero"
      ],
      "related": [
        "invoice-retry-creates-duplicate-invoices",
        "zapier-sheets-to-xero-missing-columns"
      ],
      "provenance": [
        {
          "label": "Xero documents ContactID and a ContactNumber that can be set through the API, notes that contact name may stop being unique, and says archived contacts are excluded from lists unless requested.",
          "url": "https://developer.xero.com/documentation/api/accounting/contacts"
        },
        {
          "label": "Xero publishes a demo company that resets automatically and can be used for development.",
          "url": "https://central.xero.com/s/article/Use-the-demo-company"
        }
      ],
      "incoming": [
        "platform-xero",
        "collection-ledger-sync-restore-diagnosis-order"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "xero-contact-duplicates-from-sync",
          "source": "/services/xero-contact-duplicates-from-sync/",
          "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": "xero-contact-duplicates-from-sync",
          "SI-Mode": "request",
          "SI-Page": "https://data-ops.syntheticindustry.ai/services/xero-contact-duplicates-from-sync/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=xero-contact-duplicates-from-sync&source=%2Fservices%2Fxero-contact-duplicates-from-sync%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=xero-contact-duplicates-from-sync&body=SI-Outcome%3A%20xero-contact-duplicates-from-sync%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fdata-ops.syntheticindustry.ai%2Fservices%2Fxero-contact-duplicates-from-sync%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://data-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://data-ops.syntheticindustry.ai/services/xml-supplier-feed-parse-errors-import/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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": "zapier-sheets-to-xero-missing-columns",
      "type": "outcome",
      "title": "Send every mapped Google Sheets invoice field to Xero",
      "description": "One disposable row with the agreed columns makes one draft Xero invoice containing every agreed line item and amount.",
      "url": "/services/zapier-sheets-to-xero-missing-columns/",
      "updated": "2026-10-09",
      "version": 1,
      "lifecycle": "candidate",
      "platforms": [
        "zapier",
        "google-sheets",
        "xero"
      ],
      "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": [
        "invoice-retry-creates-duplicate-invoices",
        "xero-contact-duplicates-from-sync",
        "buyer-finance-manager-invoice-integration",
        "guide-zapier-field-mapping",
        "guide-sheets-xero-line-item-shape",
        "tool-workflow-value",
        "platform-zapier",
        "platform-xero",
        "tool-invoice-rounding-bench",
        "example-invoice-tax-rounding-reconciliation",
        "example-invoice-retry-identity-matrix",
        "collection-finance-invoice-integrity-checks",
        "guide-sheets-invoice-value-rendering",
        "guide-invoice-tax-amount-basis",
        "guide-invoice-create-unknown-outcome"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "zapier-sheets-to-xero-missing-columns",
          "source": "/services/zapier-sheets-to-xero-missing-columns/",
          "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": "zapier-sheets-to-xero-missing-columns",
          "SI-Mode": "request",
          "SI-Page": "https://data-ops.syntheticindustry.ai/services/zapier-sheets-to-xero-missing-columns/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=zapier-sheets-to-xero-missing-columns&source=%2Fservices%2Fzapier-sheets-to-xero-missing-columns%2F",
        "mailto": "mailto:hello@syntheticindustry.ai?subject=zapier-sheets-to-xero-missing-columns&body=SI-Outcome%3A%20zapier-sheets-to-xero-missing-columns%0ASI-Mode%3A%20request%0ASI-Page%3A%20https%3A%2F%2Fdata-ops.syntheticindustry.ai%2Fservices%2Fzapier-sheets-to-xero-missing-columns%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-finance-manager-invoice-integration",
      "type": "buyer",
      "title": "For a finance manager: make an invoice integration complete and safe to repeat",
      "description": "Define authoritative fields, duplicate rules and reconciliation before repairing a spreadsheet-to-accounting automation.",
      "slug": "finance-manager-invoice-integration",
      "url": "/buyers/finance-manager-invoice-integration/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "Zapier: action troubleshooting",
          "url": "https://help.zapier.com/hc/en-us/articles/8496037690637-Test-your-Zap-actions",
          "checked": "2026-10-10",
          "claims": [
            "The retrieved official page describes inspecting step errors, response details and outbound requests, and resolving missing values, formatting or permission problems before retry."
          ]
        }
      ],
      "related": [
        "zapier-sheets-to-xero-missing-columns",
        "guide-zapier-field-mapping",
        "tool-workflow-value"
      ],
      "sections": [
        {
          "heading": "Specify the record, not just the connection",
          "body": [
            "Write an example invoice using synthetic values: supplier/customer reference, dates, currency, line items, amounts and the agreed accounting codes. Identify which system is authoritative for each field. A connection test can succeed while the business record is incomplete or assigned to the wrong organisation."
          ],
          "items": [
            "No real supplier bank details, invoice documents or customer records in an enquiry.",
            "Name mandatory fields and validation rules.",
            "Separate account mapping from tax or accounting advice, which is not included."
          ]
        },
        {
          "heading": "Decide duplicate behaviour before retrying",
          "body": [
            "If a run fails after creating a target record, retrying can create another one. Agree a stable source reference and the intended create-versus-update behaviour. The finance owner should define how exceptions are reconciled; a provider error message does not prove that no write occurred."
          ],
          "items": [
            "Test with disposable records on an authorised route.",
            "Inspect target state before replaying a failed action.",
            "Do not bulk replay historical invoices as a diagnostic step."
          ]
        },
        {
          "heading": "What acceptance should include",
          "body": [
            "Inspect the agreed synthetic invoice in the destination with every required field, expected totals and correct organisation. Repeat the same source input and verify the agreed duplicate rule. Test a missing mandatory field and ensure it is visibly rejected or routed for review instead of silently creating incomplete accounting data."
          ],
          "items": [
            "Keep redacted source-to-target results and exception evidence.",
            "Human approval stays with the finance owner for posting or consequential live changes."
          ]
        },
        {
          "heading": "Evaluate value honestly",
          "body": [
            "Estimate time saved using your own measured case volume and effort, including checking and exceptions. Time value is not automatically cash savings: staff may use freed capacity elsewhere rather than reduce payroll. The workflow calculator uses your inputs, not a promised provider ROI or our service quote."
          ],
          "items": []
        }
      ],
      "incoming": [
        "guide-zapier-field-mapping",
        "guide-sheets-xero-line-item-shape",
        "tool-workflow-value",
        "tool-invoice-rounding-bench",
        "example-invoice-retry-identity-matrix",
        "collection-finance-invoice-integrity-checks",
        "guide-invoice-tax-amount-basis",
        "guide-invoice-create-unknown-outcome"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/buyers/finance-manager-invoice-integration/",
          "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://data-ops.syntheticindustry.ai/buyers/finance-manager-invoice-integration/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fbuyers%2Ffinance-manager-invoice-integration%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%2Fdata-ops.syntheticindustry.ai%2Fbuyers%2Ffinance-manager-invoice-integration%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-zapier-field-mapping",
      "type": "guide",
      "title": "A Zap runs, but fields are missing: trace the value from trigger to destination",
      "description": "Inspect one synthetic record through each step and separate missing input, transformation, permissions and destination validation.",
      "slug": "zapier-field-mapping",
      "url": "/guides/zapier-field-mapping/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "Zapier: action troubleshooting",
          "url": "https://help.zapier.com/hc/en-us/articles/8496037690637-Test-your-Zap-actions",
          "checked": "2026-10-10",
          "claims": [
            "The retrieved official article describes inspecting failed steps, logs, response details and outbound requests.",
            "Missing values, formatting, permissions, expired credentials and limits can cause action problems."
          ]
        }
      ],
      "related": [
        "zapier-sheets-to-xero-missing-columns",
        "buyer-finance-manager-invoice-integration",
        "tool-workflow-value"
      ],
      "sections": [
        {
          "heading": "Follow one value across the boundaries",
          "body": [
            "Choose one authorised synthetic source record with known values. Check what the trigger provided, what each transformation returned, what the action sent and what the destination stored. A workflow marked successful is not enough to prove all intended fields were mapped."
          ],
          "items": [
            "Name the destination organisation, object and field.",
            "Record whether the source value was absent, blank, transformed or rejected.",
            "Do not export real lead or invoice payloads for an enquiry."
          ]
        },
        {
          "heading": "Read the step evidence",
          "body": [
            "Zapier's retrieved troubleshooting article describes inspecting the affected step's response and outgoing request. Missing inputs may mean useful logs are absent. Distinguish an absent source field from a stale mapping, invalid format or account permission problem; those require different changes."
          ],
          "items": [
            "Compare field names and expected types, not just display labels.",
            "Resolve expired access with the account holder without sending its credential.",
            "Check the destination after a failure before assuming it contains no record."
          ]
        },
        {
          "heading": "Testing is not assumed to be a dry run",
          "body": [
            "Do not assume a button labelled Test or Replay leaves connected systems unchanged. Agree a disposable destination and review the specific action's effects before invoking it. Lead creation, invoice creation and notification can have consequences even with made-up input. The operator needs written authority for the named test route."
          ],
          "items": [
            "Use a stable synthetic reference to identify created records.",
            "Test the create-versus-update or duplicate rule.",
            "Avoid bulk replay until reconciliation and recovery are agreed."
          ]
        },
        {
          "heading": "Prove the complete business record",
          "body": [
            "Acceptance should show the required values in the intended target record, correct object/account mapping and a controlled missing-field case. Keep redacted before-and-after step evidence and any remaining exclusions. Credentials, client access and purchases are not part of first-contact diagnosis; scope is confirmed before private work."
          ],
          "items": []
        }
      ],
      "platforms": [
        "zapier"
      ],
      "incoming": [
        "buyer-finance-manager-invoice-integration",
        "guide-sheets-xero-line-item-shape",
        "tool-workflow-value",
        "platform-zapier",
        "guide-sheets-invoice-value-rendering",
        "guide-invoice-create-unknown-outcome"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/zapier-field-mapping/",
          "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://data-ops.syntheticindustry.ai/guides/zapier-field-mapping/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fzapier-field-mapping%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%2Fdata-ops.syntheticindustry.ai%2Fguides%2Fzapier-field-mapping%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-sheets-xero-line-item-shape",
      "type": "guide",
      "title": "One Sheets row becomes one Xero invoice line: check the line-item shape",
      "description": "Distinguish missing spreadsheet headers from multiple products mapped into one invoice line, using a disposable two-product acceptance case.",
      "slug": "sheets-xero-line-item-shape",
      "url": "/guides/sheets-xero-line-item-shape/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "zapier",
        "google-sheets",
        "xero"
      ],
      "provenance": [
        {
          "label": "Canonical SI offer: five mapped fields and one draft invoice, not arbitrary workbook transformation",
          "checked": "2026-10-11",
          "claims": [
            "The existing offer excludes variable many-to-many transformation and live invoice sending. The guide's two-product arithmetic and acceptance checklist are authored proposals derived from this scope, not an executed integration or a provider-documented configuration recipe."
          ],
          "url": "https://data-ops.syntheticindustry.ai/services/zapier-sheets-to-xero-missing-columns/"
        }
      ],
      "related": [
        "zapier-sheets-to-xero-missing-columns",
        "guide-zapier-field-mapping",
        "buyer-finance-manager-invoice-integration",
        "tool-workflow-value"
      ],
      "sections": [
        {
          "heading": "Identify which of three different things is missing",
          "body": [
            "If a column is absent from the trigger sample, inspect the header and sample before editing Xero. If the trigger contains both products but the action exposes only one product's values, inspect the transformation and action mapping. If the action receives both products but the draft invoice has one merged description or the wrong amount, inspect how those values are represented as invoice lines. A successful Zap run does not distinguish these cases."
          ],
          "items": [
            "Record whether your source is one row with several product columns, several rows for one invoice, or already structured line items.",
            "Write down the number of invoices and lines you expect before changing the Zap.",
            "Do not assume a comma-separated description is two invoice lines, or that looping over two products should create two invoices."
          ]
        },
        {
          "heading": "Use a small example that makes a collapsed line obvious",
          "body": [
            "This is an invented test specification, not a tested integration or accounting advice. In an authorised demo context, use product A with quantity 2 and unit amount 10, and product B with quantity 1 and unit amount 7. With tax excluded solely for this synthetic arithmetic example, the expected line amounts are 20 and 7 and the total is 27. The result should be one unsent draft with two separate lines, not one line worth 27 and not two invoices. Your finance owner specifies actual currency, account and tax rules separately."
          ],
          "items": [
            "Use two clearly different descriptions and quantities so misaligned positions are visible.",
            "Compare each description with its own quantity, unit amount and resulting line amount; a correct grand total can conceal swapped lines.",
            "Use the finance owner's authorised demo or disposable draft route. Test buttons can create records; do not connect this example to real customers."
          ]
        },
        {
          "heading": "Keep the line-item attributes aligned",
          "body": [
            "This checklist specifies the business result; it does not establish which current Zapier action or formatter supports your source layout. The authorised implementer must confirm that separately before agreeing the repair. Inspect the proposed output before the invoice step: each description must remain paired with the intended quantity, amount and agreed accounting attributes. A correct total alone cannot show whether two products retained their separate identities."
          ],
          "items": [
            "A blank second description paired with a second amount should be caught rather than silently omitted.",
            "Variable-length product groups, several source rows per invoice or grouping several customers are larger transformation problems; do not squeeze them into a five-field remapping quote.",
            "Do not bulk replay runs to test the transformation. Inspect destination state first and agree how repeated source references are handled."
          ]
        },
        {
          "heading": "What a useful enquiry contains",
          "body": [
            "For the existing Sheets-to-Xero mapping service, send synthetic headers, whether one row already triggers the Zap, expected invoice and line counts, and the point where the second product disappears. State who owns the Xero organisation, can approve a disposable draft test and can decide on the posted price. We confirm whether the bounded field-mapping offer fits; variable line-item transformation needs a separate scope, not a hidden extension of that price."
          ],
          "items": [
            "Do not send customer names, bank details, invoice exports, credentials or access invitations initially.",
            "Keep the expected and actual line counts in the enquiry even if the Zap shows success.",
            "After agreement, acceptance also needs the agreed repeated-input and missing-field checks; no live invoice is sent by this diagnostic guide."
          ]
        }
      ],
      "incoming": [
        "example-invoice-tax-rounding-reconciliation",
        "collection-finance-invoice-integrity-checks",
        "guide-sheets-invoice-value-rendering"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/sheets-xero-line-item-shape/",
          "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://data-ops.syntheticindustry.ai/guides/sheets-xero-line-item-shape/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fsheets-xero-line-item-shape%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%2Fdata-ops.syntheticindustry.ai%2Fguides%2Fsheets-xero-line-item-shape%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": "tool-workflow-value",
      "type": "tool",
      "tool_kind": "workflow-value",
      "title": "Workflow time-value calculator: show the assumptions behind automation payback",
      "description": "Use your own time, volume, cost and running-cost inputs to calculate simple monthly value and payback; not a quote or guaranteed saving.",
      "slug": "workflow-value",
      "url": "/tools/workflow-value/",
      "version": 3,
      "lifecycle": "candidate",
      "updated": "2026-10-10",
      "provenance": [
        {
          "label": "Calculator implementation",
          "url": "https://syntheticindustry.ai/demand.js",
          "checked": "2026-10-10",
          "claims": [
            "Hours equal minutes per case times cases per month divided by 60.",
            "Gross monthly time value equals those hours times hourly cost; net subtracts monthly running cost.",
            "Payback is setup cost divided by positive net monthly value; otherwise there is no positive payback.",
            "Inputs must be finite non-negative numbers no greater than 100000000."
          ]
        }
      ],
      "related": [
        "buyer-finance-manager-invoice-integration",
        "guide-zapier-field-mapping",
        "zapier-sheets-to-xero-missing-columns"
      ],
      "sections": [
        {
          "heading": "Enter savings, not total workflow duration",
          "body": [
            "Use the minutes you expect to remove from each case, not all minutes currently spent if checking and exceptions will remain. Supply cases per month, hourly cost, one-time setup cost and monthly running cost. All monetary values must use the same currency. Your inputs are assumptions; the page has no measured volume, provider benchmark or quoted service price."
          ],
          "items": [
            "Use observed baseline timing when available.",
            "Subtract expected exception-handling and review effort from the minutes saved.",
            "Include provider fees in running cost where applicable."
          ]
        },
        {
          "heading": "The arithmetic",
          "body": [
            "Monthly hours = minutes saved per case × monthly cases ÷ 60. Gross monthly time value = hours × hourly cost. Net monthly value = gross value − monthly running cost. Simple payback = setup cost ÷ positive net monthly value. A zero or negative net value has no positive payback under these assumptions."
          ],
          "items": [
            "Worked arithmetic, not an observed case: 10 minutes × 120 cases ÷ 60 = 20 hours.",
            "At 30 per hour, gross value is 600; running cost of 100 leaves 500.",
            "Setup cost of 1500 divided by 500 gives three months; none of these inputs is our quote or a proven saving."
          ]
        },
        {
          "heading": "Time value is not cash received",
          "body": [
            "Freed time may allow other work without reducing payroll. Taxes, financing, changing volumes, implementation delays and new ongoing exceptions are not modelled. A positive result does not prove that an integration can be safely delivered or that a buyer will pay for it. Test the complete business record and duplicate behaviour separately."
          ],
          "items": [
            "Compare conservative and optimistic input assumptions.",
            "Measure the actual workflow after an authorised delivery before claiming savings."
          ]
        },
        {
          "heading": "Local calculation and its limits",
          "body": [
            "The inspected calculator computes from numeric browser inputs; it does not submit or store these values. Do not enter confidential figures if you do not want them visible on your screen. An enquiry is separate from this calculator, not an automatic payment or quote."
          ],
          "items": []
        }
      ],
      "incoming": [
        "buyer-finance-manager-invoice-integration",
        "guide-zapier-field-mapping",
        "guide-sheets-xero-line-item-shape"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/tools/workflow-value/",
          "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://data-ops.syntheticindustry.ai/tools/workflow-value/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Ftools%2Fworkflow-value%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%2Fdata-ops.syntheticindustry.ai%2Ftools%2Fworkflow-value%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-zapier",
      "type": "platform",
      "title": "Zapier automations: what repeats, what stops and who is told",
      "description": "The documented behaviours behind duplicate records, switched-off Zaps, late alerts and scheduled runs, and which outcome fits each problem.",
      "url": "/platforms/zapier/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "provenance": [
        {
          "label": "Zapier: how Zapier handles duplicate data",
          "url": "https://help.zapier.com/hc/en-us/articles/8496260269965-How-Zapier-handles-duplicate-data-in-Zap-workflows",
          "checked": "2026-10-11",
          "claims": [
            "De-duplication of polling triggers checks only within one Zap, and an action on an app that allows duplicates creates a duplicate record."
          ]
        },
        {
          "label": "Zapier: troubleshoot errors in Zap workflows",
          "url": "https://help.zapier.com/hc/en-us/articles/8496037690637-How-to-troubleshoot-errors-in-Zap-workflows",
          "checked": "2026-10-11",
          "claims": [
            "A Zap turns off automatically if 95% of its runs result in errors in the last 7 days; halted runs do not count."
          ]
        },
        {
          "label": "Zapier: what is replay",
          "url": "https://help.zapier.com/hc/en-us/articles/19220226086797-What-is-replay",
          "checked": "2026-10-11",
          "claims": [
            "Replay from history retries only errored steps, replay from the editor re-runs every step, and error emails wait for the final autoreplay attempt."
          ]
        },
        {
          "label": "Zapier: schedule Zap workflows",
          "url": "https://help.zapier.com/hc/en-us/articles/8496288648461-Schedule-Zap-workflows-to-run-at-specific-intervals",
          "checked": "2026-10-11",
          "claims": [
            "Schedule triggers use the Zapier account's time zone, not the Zap's."
          ]
        }
      ],
      "related": [
        "guide-zapier-field-mapping",
        "zapier-sheets-to-xero-missing-columns"
      ],
      "sections": [
        {
          "heading": "Four things Zapier does that surprise people",
          "body": [
            "A Zap looks simple, but several documented behaviours decide whether it can be trusted. De-duplication for polling triggers compares item IDs, but only inside one Zap, so two Zaps on one trigger both fire, and it does not stop an action creating a second record. A Zap that errors on 95% of its runs over seven days is switched off by Zapier. Replay comes in two kinds: from history it repeats only errored steps, from the editor it repeats every step. And scheduled Zaps follow the account's time zone, not the Zap's."
          ],
          "items": []
        },
        {
          "heading": "Failure is quiet unless someone arranges it",
          "body": [
            "With Autoreplay on, error emails and Zapier Manager triggers wait until the final attempt fails, so the first person to hear may hear about ten and a half hours late. A custom error handler turns the standard emails off. Halted runs, which are deliberate stops often caused by a search finding nothing, are described separately from errors and do not switch the Zap off, so they are easy to overlook. If an important Zap matters daily, someone has to decide who is told, test it with a deliberate failure on a copy, and look at run history from time to time."
          ],
          "items": []
        },
        {
          "heading": "Choose the outcome that matches the symptom",
          "body": [
            "Records appear twice: the duplicate-records outcome examines one Zap and one create step. A Facebook Lead Ads Zap shows a sample lead but no live ones: the existing Facebook-to-Salesforce outcome. Fields go missing on the way to Xero: the existing Sheets-to-Xero mapping outcome. Nobody is told when Zaps fail: the failure-alerts outcome covers up to five named automations. Zaps fail now and then and nobody has time to watch: the standing monitor-and-repair service. Each is separate, with its own test and its own boundaries."
          ],
          "items": [
            "Duplicate records: one Zap, one create step, three synthetic sends and a replay.",
            "Alerts: a deliberate failure on a copy reaches a shared place and two named people.",
            "Standing monitoring: weekly review and up to two repairs a month, no response-time promise."
          ]
        },
        {
          "heading": "Safe first contact",
          "body": [
            "Describe the Zap's trigger and destination, what you see and when it started. Do not send passwords, API keys, customer lists, invoices or an account invitation. Fit, scope and price are confirmed in writing before any access, and we work on a copy with synthetic data. Every price on the linked outcome pages is an untested proposal, and payment for fixed jobs follows the agreed checks and your sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/platforms/zapier/",
          "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://data-ops.syntheticindustry.ai/platforms/zapier/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fplatforms%2Fzapier%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%2Fdata-ops.syntheticindustry.ai%2Fplatforms%2Fzapier%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://data-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://data-ops.syntheticindustry.ai/examples/xml-feed-first-error-cases/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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://data-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://data-ops.syntheticindustry.ai/guides/mapping-supplier-category-unmapped-queue/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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://data-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://data-ops.syntheticindustry.ai/platforms/csv-files/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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://data-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://data-ops.syntheticindustry.ai/platforms/xml-feeds/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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": "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": [
        "buyer-distributor-supplier-feed-owner",
        "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://data-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://data-ops.syntheticindustry.ai/buyers/feed-operations-manager-supplier-file-delivery/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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": "example-recon-stripe-payout-composition",
      "type": "example",
      "title": "Synthetic Stripe payout: five charges, two refunds, one deposit and a clearing balance that returns to zero",
      "description": "A worked, invented payout shows how gross charges, fees and refunds add up to the single bank deposit and what ledger entries make the bank line match.",
      "url": "/examples/recon-stripe-payout-composition/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "stripe",
        "xero",
        "quickbooks-online"
      ],
      "buyer_role": "Bookkeeper checking whether a payout-level entry design would reconcile",
      "purchase_trigger": "A bank deposit equals many sales minus fees and refunds and matches no single ledger entry",
      "problem": "The ledger holds gross sales while the bank holds one net batch with no link between them.",
      "related": [
        "payout-stripe-deposit-matches-bank-line"
      ],
      "provenance": [
        {
          "label": "Stripe: payout reconciliation",
          "url": "https://docs.stripe.com/payouts/reconciliation",
          "checked": "2026-10-11",
          "claims": [
            "An automatic payout can include funds from many transactions, and the balance transactions for one payout can be listed by passing the payout id.",
            "Balance transaction types include charge, refund, stripe_fee and the payout itself.",
            "For manual payouts Stripe cannot identify which transactions are included, so the user must reconcile them against transaction history; a payout.reconciliation_completed event signals when reconciliation data is ready."
          ]
        },
        {
          "label": "Stripe: payout reconciliation report",
          "url": "https://docs.stripe.com/reports/payout-reconciliation",
          "checked": "2026-10-11",
          "claims": [
            "The report groups each automatic payout's transactions by reporting category and offers summary and itemised downloads, and is not available to manual or instant payout users in the same way.",
            "The report groups a payout by its estimated arrival date, not the date the bank posts the deposit, and report data follows a separate processing schedule so a payout can arrive before its data is ready."
          ]
        },
        {
          "label": "Stripe: refunds",
          "url": "https://docs.stripe.com/refunds",
          "checked": "2026-10-11",
          "claims": [
            "Stripe's processing fees from the original transaction are not returned when a payment is refunded, and more than one refund can be issued against a charge up to the original amount.",
            "A refund can fail and the amount be returned to the Stripe balance, which can take up to 30 days from the post date."
          ]
        }
      ],
      "sections": [
        {
          "heading": "Invented inputs, not a real payout or fee schedule",
          "body": [
            "All amounts are invented, in GBP. The fee rule (1.5 percent plus 20p per charge, rounded half up to the penny) is made up for arithmetic and is not Stripe's pricing. Five charges, A to E, are paid out together; a full refund of charge B and a partial refund of 20.00 on charge C are also in this payout. Following Stripe's documented behaviour, the processing fee on a refunded charge is not returned."
          ],
          "items": [],
          "code": "item        type     gross      fee      net\ncharge A    charge    120.00     2.00   118.00\ncharge B    charge     45.50     0.88    44.62\ncharge C    charge     80.00     1.40    78.60\ncharge D    charge     19.99     0.50    19.49\ncharge E    charge    250.00     3.95   246.05\nrefund B    refund    -45.50     0.00   -45.50\nrefund C    refund    -20.00     0.00   -20.00\n\ngross charges            = 515.49\nfees (not returned on refunds) = 8.73\nrefunds                  = 65.50\npayout = 515.49 - 8.73 - 65.50 = 441.26"
        },
        {
          "heading": "The ledger entries that make the bank line match",
          "body": [
            "Sales are recorded gross against a clearing account, fees and refunds are recorded against the same clearing account from the payout's own transaction list, and one payout-level entry moves the net amount from clearing to the bank. After it, clearing returns to zero for this payout and the bank deposit equals one ledger entry. Which account types and entry forms you use is your accountant's decision; this is a shape, not a recommendation."
          ],
          "items": [],
          "code": "ledger entry                         clearing   bank\nsales A-E, gross                     +  515.49\nprocessing fees                      -    8.73\nrefunds B and C                      -   65.50\npayout PO-SYN-1 (clearing -> bank)   -  441.26  +441.26\nclearing balance after payout             0.00"
        },
        {
          "heading": "What the example does not prove",
          "body": [
            "The arithmetic in this example was recomputed independently, and that is all it shows. No Stripe account, payout, API, accounting file or bank was used, and no real fee was calculated. Manual and instant payouts cannot be tied to transactions this way, and multi-currency payouts, disputes and fee tax are outside the example."
          ],
          "items": [
            "A payout's arrival date in Stripe's report can differ from the bank's posting date.",
            "Real exports have more categories than this example shows."
          ]
        },
        {
          "heading": "Using the example",
          "body": [
            "Compare your own payout, using only totals, with this shape. If one payout in your data has this structure and no single ledger entry equals the deposit, the fixed-price job \"Make every Stripe payout match one bank deposit line in Xero or QuickBooks Online\" (from £495, an untested published price confirmed after your enquiry, payment after the agreed checks pass and you sign off) is relevant. Acceptance includes one ledger entry per test payout equal to the deposit and a clearing balance equal to only the unpaid transactions. Send invented examples and counts first, never credentials, bank details, invoices or customer records; real records are handled only after written agreement through a secure handoff."
          ],
          "items": []
        }
      ],
      "incoming": [
        "collection-recon-payment-to-ledger-diagnosis-order"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/recon-stripe-payout-composition/",
          "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://data-ops.syntheticindustry.ai/examples/recon-stripe-payout-composition/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Frecon-stripe-payout-composition%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%2Fdata-ops.syntheticindustry.ai%2Fexamples%2Frecon-stripe-payout-composition%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-invoice-currency-rate-direction-check",
      "type": "example",
      "title": "Synthetic foreign-currency check: the same 100.00 USD order with Xero-style and QuickBooks-style rates",
      "description": "Invented arithmetic shows how a copied, inverted or default rate changes the base total, and how treating minor units as whole units shrinks a yen amount a hundredfold.",
      "url": "/examples/invoice-currency-rate-direction-check/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "xero",
        "quickbooks-online",
        "stripe"
      ],
      "buyer_role": "Developer or bookkeeper writing acceptance checks for a foreign-currency sync",
      "purchase_trigger": "Base totals for foreign invoices disagree with the settled amount",
      "problem": "Rate direction and amount units are not part of the acceptance checks.",
      "related": [
        "platform-xero"
      ],
      "provenance": [
        {
          "label": "Xero: multicurrency best practice",
          "url": "https://developer.xero.com/documentation/best-practices/data-integrity/multicurrency/",
          "checked": "2026-10-11",
          "claims": [
            "A CurrencyRate is expressed as foreign currency per one unit of base currency, and Xero says many integrations send the inverse.",
            "A rate of one should never be defaulted; the rate may be omitted so Xero picks one, and should be set only when a real foreign-exchange transaction took place.",
            "Currencies must be added to the organisation before multicurrency documents can use them, and currencies cannot be removed once added.",
            "Xero returns non-blocking validation warnings for rates that look inverted or out of range."
          ]
        },
        {
          "label": "Intuit: manage multiple currencies",
          "url": "https://developer.intuit.com/app/developer/qbo/docs/workflows/manage-multiple-currencies",
          "checked": "2026-10-11",
          "claims": [
            "Multicurrency can only be enabled in the QuickBooks Online product, not through the API, and cannot be disabled once enabled.",
            "Exchange rates are recorded as the number of home-currency units that equal one foreign-currency unit."
          ]
        },
        {
          "label": "Stripe: supported currencies",
          "url": "https://docs.stripe.com/currencies",
          "checked": "2026-10-11",
          "claims": [
            "All API amounts are in the currency's smallest unit, so 1000 is 10.00 for a two-decimal currency, while for a zero-decimal currency such as JPY 10 means 10 yen.",
            "ISK and UGX must be represented as two-decimal values with the decimals always 00, and HUF and TWD are zero-decimal for payouts."
          ]
        }
      ],
      "sections": [
        {
          "heading": "Invented order and the four ways to get the base total wrong",
          "body": [
            "One invented order of 100.00 USD is invoiced in a GBP file at an invented 1.25 USD per 1 GBP, so the correct base total is 80.00 GBP. Xero expresses a rate as foreign per one unit of base, and QuickBooks Online expresses it as home units per one foreign unit, so the stored numbers differ. The lower block shows source amounts in the smallest currency unit."
          ],
          "items": [],
          "code": "invented order: 100.00 USD, home currency GBP, 1.25 USD per 1 GBP\n\ntarget style              stored rate   base total            check\nXero (foreign per base)   1.25          100.00 / 1.25 = 80.00   correct\nQuickBooks (home/foreign) 0.80          100.00 x 0.80 = 80.00   correct\nXero, copied 0.80         0.80          100.00 / 0.80 = 125.00  WRONG, +45.00\nQuickBooks, copied 1.25   1.25          100.00 x 1.25 = 125.00  WRONG, +45.00\ndefault rate of one       1.00          100.00 / 1.00 = 100.00  WRONG for a real conversion\n\nsource amounts in the smallest unit (Stripe style)\ncurrency  source amount  decimals  correct value   if divided by 100\nGBP       1099           2         10.99           10.99\nUSD       10000          2         100.00          100.00\nJPY       5000           0         5,000           50  (WRONG)"
        },
        {
          "heading": "Checks this gives you",
          "body": [
            "For each foreign test invoice recompute the base total from the stored rate in the target's documented direction and compare it with the expected base total; a mismatch of this size is never rounding. Assert that no foreign invoice carries a rate of one unless an agreed rule names it. For each source field state whether it is in minor or whole units and test one zero-decimal currency."
          ],
          "items": [
            "An inverted rate gives a base total wrong by a factor equal to the rate squared (here 1.5625, so 80.00 becomes 125.00), which is never rounding.",
            "A value wrong by exactly 100 is typical of a minor-unit mistake in a zero-decimal currency.",
            "An order in a currency not enabled in the file should be held, not posted in the home currency."
          ]
        },
        {
          "heading": "What was and was not exercised",
          "body": [
            "The arithmetic was recomputed independently. No exchange-rate source, Xero organisation, QuickBooks company or payment account was used, and 1.25 is not a market rate. Xero documents its direction and says never to default a rate of one; Intuit documents the opposite direction and that multicurrency cannot be disabled once enabled; Stripe documents smallest-unit amounts and zero-decimal currencies."
          ],
          "items": []
        },
        {
          "heading": "Using the example",
          "body": [
            "The fixed-price job \"Make foreign-currency orders create invoices in the right currency, with the right rate\" is from £395 for up to three currencies, an untested published price confirmed after your enquiry, with payment after the agreed checks pass and you sign off. Its acceptance tests are these checks on your invented orders. Which rate to use remains your accountant's decision. Send invented examples and counts first, never credentials, bank details, invoices or customer records; real records are handled only after written agreement through a secure handoff."
          ],
          "items": []
        }
      ],
      "incoming": [],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/invoice-currency-rate-direction-check/",
          "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://data-ops.syntheticindustry.ai/examples/invoice-currency-rate-direction-check/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Finvoice-currency-rate-direction-check%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%2Fdata-ops.syntheticindustry.ai%2Fexamples%2Finvoice-currency-rate-direction-check%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-xero",
      "type": "platform",
      "title": "Xero integrations: identity, limits, accounts and currency decide whether a sync can be trusted",
      "description": "What Xero documents for integration builders (contacts, invoice numbers, idempotency, paging, limits, accounts, lock dates, demo company) and which failures map to which guide or outcome.",
      "url": "/platforms/xero/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "xero"
      ],
      "related": [
        "xero-contact-duplicates-from-sync",
        "invoice-retry-creates-duplicate-invoices",
        "zapier-sheets-to-xero-missing-columns"
      ],
      "provenance": [
        {
          "label": "Xero Accounting API: contacts",
          "url": "https://developer.xero.com/documentation/api/accounting/contacts",
          "checked": "2026-10-11",
          "claims": [
            "ContactID is the identifier Xero recommends for referencing a contact, and Xero warns contact name may stop being unique in future.",
            "ContactNumber (up to 50 characters) can be set through the API and is shown in the Xero interface as Contact Code; AccountNumber is user-defined and is not stated to be unique.",
            "A PUT only creates and returns an error if an existing contact matches the name or contact number, while a POST can create or update.",
            "Archived contacts are left out of contact lists unless includeArchived is requested."
          ]
        },
        {
          "label": "Xero: limits FAQ",
          "url": "https://developer.xero.com/faq/limits",
          "checked": "2026-10-11",
          "claims": [
            "At the time checked the FAQ states per-connected-organisation limits of 60 calls per minute, 5 concurrent calls and a daily limit (5,000 per 24 hours), plus 10,000 calls per minute across all organisations for an app.",
            "Going over a limit returns HTTP 429 with a Retry-After header giving seconds to wait; responses carry headers showing the remaining daily, minute and app-minute allowance.",
            "Xero suggests combining creates or updates in one request (about 50 items is practical under the 3.5MB size cap), paging (100 records at a time) and the If-Modified-Since header."
          ]
        },
        {
          "label": "Xero: OAuth 2.0 FAQ",
          "url": "https://developer.xero.com/faq/oauth2",
          "checked": "2026-10-11",
          "claims": [
            "Access tokens last 30 minutes and unused refresh tokens expire after 60 days, after which the user must authorise the app again.",
            "Each successful refresh returns a new refresh token that must be stored in place of the old one.",
            "If a refresh request gets no response, the previous refresh token can be retried for 30 minutes before the user must re-authorise."
          ]
        },
        {
          "label": "Xero: idempotent requests",
          "url": "https://developer.xero.com/documentation/guides/idempotent-requests/idempotency/",
          "checked": "2026-10-11",
          "claims": [
            "Xero accepts an Idempotency-Key header on POST, PUT and PATCH requests and ignores it on other methods.",
            "A key is kept for six minutes from its first use, may be at most 128 characters, is checked per app, and re-using it with a different request returns a 400.",
            "An error cached against a key is returned again on re-run, and idempotency is checked after rate limits so repeated calls still count toward them.",
            "Xero advises checking with a GET whether a resource was already created before retrying with a new key."
          ]
        },
        {
          "label": "Xero: account and payment mapping",
          "url": "https://developer.xero.com/documentation/best-practices/categorising-transactions/account-mapping/",
          "checked": "2026-10-11",
          "claims": [
            "Integrations should let users choose accounts from a filtered list, exclude accounts with status ARCHIVED, and not hard-code an account such as the sales account.",
            "Users can change their chart of accounts after set-up, so Xero advises validating stored mappings, before each call for infrequent integrations, and sending the user back to fix a missing or archived account.",
            "Payment accounts are filtered by account type BANK or by EnablePaymentsToAccount."
          ]
        },
        {
          "label": "Xero: the demo company",
          "url": "https://central.xero.com/s/article/Use-the-demo-company",
          "checked": "2026-10-11",
          "claims": [
            "Data added to the demo company is deleted when it resets automatically after 28 days, and it can be reset manually.",
            "Invoices cannot be sent from the demo company, and only the person who adds data can see it."
          ]
        }
      ],
      "sections": [
        {
          "heading": "What Xero gives an integration builder",
          "body": [
            "Xero documents stable identifiers (a contact's ContactID and a ContactNumber you can set through the API), a unique invoice number for sales invoices, an Idempotency-Key header that is kept for six minutes, paging with a pagination object, an If-Modified-Since header for incremental reads, per-organisation limits with a Retry-After response, a chart of accounts with active and archived accounts, lock dates, and a demo company that resets itself after 28 days. A trustworthy sync uses these deliberately; most failures come from using text that changes or limits that nobody read."
          ],
          "items": [
            "Identity: store ContactID or your own number in ContactNumber; do not match on names alone.",
            "Limits: 60 calls a minute and 5 concurrent calls per organisation at the time checked, with a daily limit.",
            "Connection: refresh tokens lapse after 60 days of non-use."
          ]
        },
        {
          "heading": "Failure families and where to go next",
          "body": [
            "Customers split across contacts, orders missing after a busy run, lines posting to the wrong account, foreign invoices with the wrong rate, expense bills without receipts, duplicate invoices after a retry and a sync that has quietly stopped are different failures with different fixes. Each has a guide that explains the mechanism, a safe first investigation and the point at which a paid, bounded job fits."
          ],
          "items": [
            "Duplicate contacts: the contact identity guide and the contact job.",
            "Missing orders: the rate-limit guide and its pacing and checkpoint job.",
            "Wrong accounts: the mapping-table guide and its fixed-price job.",
            "Wrong currency or rate: the currency direction guide and job.",
            "Duplicate invoices: the request-key guide and the retry-safety job.",
            "A sync that stopped: the refresh-token guide and the standing health service."
          ]
        },
        {
          "heading": "A safe test looks like this",
          "body": [
            "Test against the Xero demo company, never live records. Use invented customers, orders and amounts; do not send invoices; expect the demo data to disappear when it resets. Keep counts and identifiers from each step so you can show what changed. Lock dates and bank-reconciled transactions are decisions for the organisation's administrator and accountant."
          ],
          "items": []
        },
        {
          "heading": "Choose the actual outcome",
          "body": [
            "Fixing one known failure is a bounded job. Several failures at once, in an order that matters, is a project. Watching a sync month after month is a standing service. None of them includes bookkeeping, tax or audit advice, changes to posted or locked records or live changes under our control; your authorised account holder applies changes. Prices on the linked pages are untested published prices, and nothing starts without a written agreement."
          ],
          "items": [
            "The first enquiry uses invented examples, not credentials, invoices or customer records.",
            "Real records are shared only after agreement, through a secure handoff."
          ]
        }
      ],
      "incoming": [
        "example-invoice-currency-rate-direction-check"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/platforms/xero/",
          "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://data-ops.syntheticindustry.ai/platforms/xero/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fplatforms%2Fxero%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%2Fdata-ops.syntheticindustry.ai%2Fplatforms%2Fxero%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-recon-bookkeeper-payments-to-ledger",
      "type": "buyer",
      "title": "For a bookkeeper: make payment-processor activity reconcile to the ledger without rebuilding it every month",
      "description": "Questions, evidence and decisions for a bookkeeper who inherits a processor-to-ledger integration that never quite agrees with the bank.",
      "url": "/buyers/recon-bookkeeper-payments-to-ledger/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "stripe",
        "paypal",
        "xero",
        "quickbooks-online"
      ],
      "related": [
        "payout-stripe-deposit-matches-bank-line",
        "collection-recon-payment-to-ledger-diagnosis-order"
      ],
      "provenance": [
        {
          "label": "Stripe: payout reconciliation report",
          "url": "https://docs.stripe.com/reports/payout-reconciliation",
          "checked": "2026-10-11",
          "claims": [
            "The report groups each automatic payout's transactions by reporting category and offers summary and itemised downloads, and is not available to manual or instant payout users in the same way.",
            "The report groups a payout by its estimated arrival date, not the date the bank posts the deposit, and report data follows a separate processing schedule so a payout can arrive before its data is ready."
          ]
        },
        {
          "label": "PayPal: Transaction Search API",
          "url": "https://developer.paypal.com/docs/api/transaction-search/v1/",
          "checked": "2026-10-11",
          "claims": [
            "The list transactions call supports a maximum date range of 31 days, requires an end date, and can take up to three hours for executed transactions to appear.",
            "Page size defaults to 100 and can be up to 500, and the call covers the previous three years.",
            "Each transaction carries an event code, an amount and a fee amount.",
            "A transaction identifier is not unique in the reporting data: the response can list two records with the same identifier, one affecting the balance and one not."
          ]
        },
        {
          "label": "Xero: lock dates",
          "url": "https://central.xero.com/0/article/Set-up-and-work-with-lock-dates",
          "checked": "2026-10-11",
          "claims": [
            "Lock dates stop changes to past transactions, and the article names administrators as the users who can set or change them."
          ]
        }
      ],
      "sections": [
        {
          "heading": "Start with what the integration records, not what it should",
          "body": [
            "Take one closed month and list, for each flow (sales, payouts, refunds, fees), what the integration writes to the ledger and with which processor identifier. A flow with no identifier on its ledger entries cannot be matched automatically, and that single finding usually explains why reconciliation is manual. Keep this list; it is the brief for anyone you ask to help."
          ],
          "items": [
            "Which flows reach the ledger, and as what kind of entry?",
            "Is the processor's identifier stored on each entry?",
            "Is there a clearing account, or do sales go straight to the bank?"
          ]
        },
        {
          "heading": "Gather evidence you can share safely",
          "body": [
            "Totals and counts per flow and currency for one month, from the processor's report and from the ledger, are enough for a first conversation. Do not send exports, customer names, bank details or credentials. Say which payouts are automatic and which are manual or instant, because Stripe says it cannot tie manual or instant payouts to specific transactions, and other processors may differ."
          ],
          "items": [
            "Counts and totals for payouts, refunds and fees on both sides.",
            "The payout schedule and the settlement currency.",
            "Whether any part of the month falls in a locked period."
          ]
        },
        {
          "heading": "Decisions that are yours",
          "body": [
            "How a payout, a refund and a fee should appear in your ledger, what tolerance is acceptable, which date defines the period and how a locked period is handled are decisions for you and the accountant. A software job records and applies them; it does not make them. Corrections to posted records stay with you."
          ],
          "items": []
        },
        {
          "heading": "Choose the right size of help",
          "body": [
            "One flow that is plainly wrong is a bounded job: for example the Stripe payout job, from £495, or the PayPal refunds job, from £445. Several flows together make a project, from £3,950, and keeping it true afterwards is a standing monthly check, £295 a month. All prices are untested and confirmed after an enquiry; payment follows agreed checks and your sign-off, and none of them is bookkeeping, tax or audit advice. Send invented examples and counts first, never credentials, bank details, invoices or customer records; real records are handled only after written agreement through a secure handoff."
          ],
          "items": []
        }
      ],
      "incoming": [
        "collection-recon-payment-to-ledger-diagnosis-order"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/buyers/recon-bookkeeper-payments-to-ledger/",
          "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://data-ops.syntheticindustry.ai/buyers/recon-bookkeeper-payments-to-ledger/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fbuyers%2Frecon-bookkeeper-payments-to-ledger%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%2Fdata-ops.syntheticindustry.ai%2Fbuyers%2Frecon-bookkeeper-payments-to-ledger%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-ledger-sync-operations-lead-integration-health",
      "type": "buyer",
      "title": "For an operations lead: know when a finance sync has stopped, duplicated work or dropped orders",
      "description": "Three counts, three owners and four questions that tell an operations lead whether a sync into the accounting system can be trusted this month.",
      "url": "/buyers/ledger-sync-operations-lead-integration-health/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "xero",
        "quickbooks-online"
      ],
      "related": [
        "invoice-retry-creates-duplicate-invoices",
        "collection-ledger-sync-restore-diagnosis-order"
      ],
      "provenance": [
        {
          "label": "Xero: OAuth 2.0 FAQ",
          "url": "https://developer.xero.com/faq/oauth2",
          "checked": "2026-10-11",
          "claims": [
            "Access tokens last 30 minutes and unused refresh tokens expire after 60 days, after which the user must authorise the app again.",
            "Each successful refresh returns a new refresh token that must be stored in place of the old one.",
            "If a refresh request gets no response, the previous refresh token can be retried for 30 minutes before the user must re-authorise."
          ]
        },
        {
          "label": "Xero: limits FAQ",
          "url": "https://developer.xero.com/faq/limits",
          "checked": "2026-10-11",
          "claims": [
            "At the time checked the FAQ states per-connected-organisation limits of 60 calls per minute, 5 concurrent calls and a daily limit (5,000 per 24 hours), plus 10,000 calls per minute across all organisations for an app.",
            "Going over a limit returns HTTP 429 with a Retry-After header giving seconds to wait; responses carry headers showing the remaining daily, minute and app-minute allowance.",
            "Xero suggests combining creates or updates in one request (about 50 items is practical under the 3.5MB size cap), paging (100 records at a time) and the If-Modified-Since header."
          ]
        },
        {
          "label": "Intuit: API call limits and throttles",
          "url": "https://static.developer.intuit.com/output_html/qbo/docs/learn/limits-and-throttles.html",
          "checked": "2026-10-11",
          "claims": [
            "The QuickBooks Online REST API allows 500 requests per minute per company and 10 requests per second per company and app, and returns HTTP 429, advising a wait of 60 seconds.",
            "Batch requests are suggested at up to 30 payloads, with throttling from 40 batch requests per minute per company and app; a query returns at most 1,000 entities."
          ]
        }
      ],
      "sections": [
        {
          "heading": "A green run is not a correct month",
          "body": [
            "A sync can finish without error and still have created too few, too many or wrongly posted documents. The measure that matters is a set of counts for the same period: source orders, documents created, orders found already present and orders held with a reason. If created plus held plus already-existing does not equal the source count, something was dropped or duplicated, whatever the run log says."
          ],
          "items": [
            "Ask your developer to report these counts for every run.",
            "Compare them with a count made in the accounting system itself."
          ]
        },
        {
          "heading": "Who owns what",
          "body": [
            "Name an owner for each of three things: the connection to the accounting system, which a person with the right role must renew when it lapses; the sync code, which your developer or vendor maintains; and the approval of exceptions, which your finance owner decides. A connection with no named owner is easy to miss: Xero says an unused refresh token expires after 60 days, and without an owner nobody is assigned to notice."
          ],
          "items": []
        },
        {
          "heading": "Four questions for your developer",
          "body": [
            "What happens when the accounting system rate-limits a run, and where is the record of orders that were skipped? How does the sync recognise an order it has already created, and what does it do when it cannot tell? When was the connection last renewed, and who is told before it lapses? What do held orders look like and who clears them? Vague answers to any of these are the work to do first."
          ],
          "items": [
            "Xero returns a wait value when a limit is hit, and Intuit advises waiting 60 seconds after a 429.",
            "A retry that cannot tell whether the first attempt worked is how duplicates start."
          ]
        },
        {
          "heading": "Choose the right size of help",
          "body": [
            "A single known fault is a bounded job, for example duplicate prevention (from £395) or pacing and a checkpoint (from £445). Several faults that interact are a project, from £2,950. Watching the sync afterwards is a standing monthly service, £345 a month, which never renews credentials itself. All prices are untested, confirmed after an enquiry, with payment after agreed checks pass and you sign off. Send invented examples and counts first, never credentials, bank details, invoices or customer records; real records are handled only after written agreement through a secure handoff."
          ],
          "items": []
        }
      ],
      "incoming": [
        "collection-ledger-sync-restore-diagnosis-order"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/buyers/ledger-sync-operations-lead-integration-health/",
          "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://data-ops.syntheticindustry.ai/buyers/ledger-sync-operations-lead-integration-health/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fbuyers%2Fledger-sync-operations-lead-integration-health%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%2Fdata-ops.syntheticindustry.ai%2Fbuyers%2Fledger-sync-operations-lead-integration-health%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-recon-payment-to-ledger-diagnosis-order",
      "type": "category",
      "title": "Processor to ledger to bank: diagnose a month that does not reconcile, in this order",
      "description": "An ordered process map: confirm scope, payout type, payout entries, refunds and fees, duplicates, timing and report completeness before asking anyone to change an integration.",
      "url": "/collections/recon-payment-to-ledger-diagnosis-order/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "stripe",
        "paypal",
        "xero",
        "quickbooks-online"
      ],
      "buyer_role": "Bookkeeper or finance manager working through a month that does not reconcile",
      "purchase_trigger": "The bank, the processor and the ledger disagree and the cause is not obvious",
      "problem": "Differences are chased in the order they are noticed rather than the order in which one cause hides another.",
      "related": [
        "payout-stripe-deposit-matches-bank-line",
        "example-recon-stripe-payout-composition",
        "buyer-recon-bookkeeper-payments-to-ledger"
      ],
      "provenance": [
        {
          "label": "Stripe: payout reconciliation report",
          "url": "https://docs.stripe.com/reports/payout-reconciliation",
          "checked": "2026-10-11",
          "claims": [
            "The report groups each automatic payout's transactions by reporting category and offers summary and itemised downloads, and is not available to manual or instant payout users in the same way.",
            "The report groups a payout by its estimated arrival date, not the date the bank posts the deposit, and report data follows a separate processing schedule so a payout can arrive before its data is ready."
          ]
        },
        {
          "label": "PayPal: Transaction Search API",
          "url": "https://developer.paypal.com/docs/api/transaction-search/v1/",
          "checked": "2026-10-11",
          "claims": [
            "The list transactions call supports a maximum date range of 31 days, requires an end date, and can take up to three hours for executed transactions to appear.",
            "Page size defaults to 100 and can be up to 500, and the call covers the previous three years.",
            "Each transaction carries an event code, an amount and a fee amount.",
            "A transaction identifier is not unique in the reporting data: the response can list two records with the same identifier, one affecting the balance and one not."
          ]
        },
        {
          "label": "Xero: lock dates",
          "url": "https://central.xero.com/0/article/Set-up-and-work-with-lock-dates",
          "checked": "2026-10-11",
          "claims": [
            "Lock dates stop changes to past transactions, and the article names administrators as the users who can set or change them."
          ]
        }
      ],
      "sections": [
        {
          "heading": "Use the order, and stop at the first step that fails",
          "body": [
            "Each step can hide the next: a wrong period makes every total differ, and a missing payout makes refunds look wrong. Work in this order with invented or redacted figures, recording the result of each step before moving on. This is a diagnostic sequence, not a vendor procedure and not accounting advice."
          ],
          "items": [
            "1. Scope: fix the period, the time zone, the currency and the processor account. Differences caused by a different window are not integration faults.",
            "2. Payout type: confirm whether payouts are automatic, manual or instant. Only automatic payouts can be tied to their transactions by the processor (see the payout guide).",
            "3. Payout entries: for each payout, is there one ledger entry equal to the deposit, and does the clearing account return to zero for it? (See the Stripe payout example.)",
            "4. Refunds and fees: do the processor's refund and fee totals match the ledger, linked by identifier? (See the refund and fee guide.)",
            "5. Duplicates and missing items: match line by line on identifiers, not totals (see the drift categories guide and the drift list example).",
            "6. Timing: apply the period rule to items near the month boundary, using the processor's arrival date and report lag.",
            "7. Report completeness: confirm any export you rely on is complete for the window (see the report windows guide)."
          ]
        },
        {
          "heading": "What to record at each step",
          "body": [
            "For every step note the counts and totals per flow and currency, the processor identifiers of any unmatched items, and whether the period is locked. Stop and ask a person with authority, usually your accountant, before anything in a locked or reconciled period is changed. The notes become the brief for a bounded job, a project or the standing monthly check."
          ],
          "items": [
            "Never alter a locked or reconciled period to make a step pass.",
            "An item explained by timing is closed only when its counterpart is found in the next period."
          ]
        },
        {
          "heading": "Which paid outcome matches which step",
          "body": [
            "Step 3 points to the Stripe payout job (from £495). Step 4 points to the PayPal refunds and fees job (from £445) when the processor is PayPal. Several failing steps point to the project (from £3,950), and a month that agrees but must stay true points to the standing check (£295 a month). All prices are untested and confirmed after an enquiry; payment follows agreed checks and your sign-off. Send invented examples and counts first, never credentials, bank details, invoices or customer records; real records are handled only after written agreement through a secure handoff."
          ],
          "items": []
        }
      ],
      "incoming": [
        "buyer-recon-bookkeeper-payments-to-ledger"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/collections/recon-payment-to-ledger-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://data-ops.syntheticindustry.ai/collections/recon-payment-to-ledger-diagnosis-order/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fcollections%2Frecon-payment-to-ledger-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%2Fdata-ops.syntheticindustry.ai%2Fcollections%2Frecon-payment-to-ledger-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": "collection-ledger-sync-restore-diagnosis-order",
      "type": "category",
      "title": "A finance sync that cannot be trusted: check these in order before re-running anything",
      "description": "An ordered process map for a broken invoice sync: connection, completeness, accounts, contact identity, retries and duplicates, updates and currency, then re-count.",
      "url": "/collections/ledger-sync-restore-diagnosis-order/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "xero",
        "quickbooks-online"
      ],
      "buyer_role": "Operations lead or developer deciding the order in which to repair a sync",
      "purchase_trigger": "A sync shows several problems at once and fixing one at a time has not helped",
      "problem": "Faults are repaired in the order they were reported, so an early fix hides or reshapes a later one.",
      "related": [
        "invoice-retry-creates-duplicate-invoices",
        "xero-contact-duplicates-from-sync",
        "buyer-ledger-sync-operations-lead-integration-health"
      ],
      "provenance": [
        {
          "label": "Xero: OAuth 2.0 FAQ",
          "url": "https://developer.xero.com/faq/oauth2",
          "checked": "2026-10-11",
          "claims": [
            "Access tokens last 30 minutes and unused refresh tokens expire after 60 days, after which the user must authorise the app again.",
            "Each successful refresh returns a new refresh token that must be stored in place of the old one.",
            "If a refresh request gets no response, the previous refresh token can be retried for 30 minutes before the user must re-authorise."
          ]
        },
        {
          "label": "Xero: limits FAQ",
          "url": "https://developer.xero.com/faq/limits",
          "checked": "2026-10-11",
          "claims": [
            "At the time checked the FAQ states per-connected-organisation limits of 60 calls per minute, 5 concurrent calls and a daily limit (5,000 per 24 hours), plus 10,000 calls per minute across all organisations for an app.",
            "Going over a limit returns HTTP 429 with a Retry-After header giving seconds to wait; responses carry headers showing the remaining daily, minute and app-minute allowance.",
            "Xero suggests combining creates or updates in one request (about 50 items is practical under the 3.5MB size cap), paging (100 records at a time) and the If-Modified-Since header."
          ]
        },
        {
          "label": "Xero: account and payment mapping",
          "url": "https://developer.xero.com/documentation/best-practices/categorising-transactions/account-mapping/",
          "checked": "2026-10-11",
          "claims": [
            "Integrations should let users choose accounts from a filtered list, exclude accounts with status ARCHIVED, and not hard-code an account such as the sales account.",
            "Users can change their chart of accounts after set-up, so Xero advises validating stored mappings, before each call for infrequent integrations, and sending the user back to fix a missing or archived account.",
            "Payment accounts are filtered by account type BANK or by EnablePaymentsToAccount."
          ]
        },
        {
          "label": "Intuit: error 5010, Stale Object Error",
          "url": "https://help.developer.intuit.com/s/article/5010-Stale-Object-Error",
          "checked": "2026-10-11",
          "claims": [
            "The error means the update did not use the latest version of the object, which is carried in its SyncToken.",
            "Intuit recommends either storing each object's identifier, type and SyncToken and refreshing them from change data capture or webhooks, or reading the object before every update."
          ]
        }
      ],
      "sections": [
        {
          "heading": "Why the order matters",
          "body": [
            "A repair can only be judged when the layer below it is sound. Checking accounts is pointless while the connection is down, and counts of created documents mean little until each order creates at most one document and every line posts to a known account. The sequence below goes from the most basic condition to the most specific. Work on invented or redacted data on a demo or sandbox target, and stop at the first step that fails. This is a diagnostic order, not a vendor procedure."
          ],
          "items": [
            "1. Connection: is the connection alive and who owns renewing it? (See the refresh-token guide.)",
            "2. Accounts: does every posted line use an active, approved account, with no default? (See the mapping-table guide.)",
            "3. Retries and duplicates: does each source order create at most one document, even after a lost response? (See the request-key guide.)",
            "4. Completeness: do source, created, already-present and held counts add up for a recent busy run, and were limits hit? (See the rate-limit guide.)",
            "5. Contact identity: does each customer map to one contact by a stored identifier? (See the contact identity guide, for Xero.)",
            "6. Updates: do edits to existing documents survive conflicts? (See the SyncToken guide, for QuickBooks Online.)",
            "7. Currency: are code, amount and rate correct in each currency? (See the currency guide.)",
            "8. Re-count: run a synthetic trading month and compare source, created, already-present and held counts again."
          ]
        },
        {
          "heading": "Record what each step shows",
          "body": [
            "Keep the counts, the identifiers of any affected documents and the error text with names removed. A step that fails becomes the first item on the failure list. Each item that has a bounded paid job is named on the relevant guide; the order in which they are fixed matters and belongs in writing."
          ],
          "items": [
            "Do not delete, void or merge real records to make a step pass; those are decisions for your finance owner or accountant.",
            "Do not re-run historical batches as a diagnostic step."
          ]
        },
        {
          "heading": "When to ask for help",
          "body": [
            "One failing step with a clear cause is a bounded job. Several failing steps that interact are the project \"Restore a broken invoice sync, proven on a synthetic trading month\", from £2,950, and keeping the sync healthy afterwards is the standing service, £345 a month. Both prices are untested and confirmed after an enquiry; payment follows agreed checks and your sign-off, and nothing here is accounting advice. Send invented examples and counts first, never credentials, bank details, invoices or customer records; real records are handled only after written agreement through a secure handoff."
          ],
          "items": []
        }
      ],
      "incoming": [
        "buyer-ledger-sync-operations-lead-integration-health"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/collections/ledger-sync-restore-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://data-ops.syntheticindustry.ai/collections/ledger-sync-restore-diagnosis-order/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fcollections%2Fledger-sync-restore-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%2Fdata-ops.syntheticindustry.ai%2Fcollections%2Fledger-sync-restore-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": "tool-invoice-rounding-bench",
      "type": "tool",
      "tool_kind": "invoice-rounding-bench",
      "title": "Invoice rounding bench: compare per-line and total rounding, half-up and half-even",
      "description": "Enter invoice lines and see net, tax and gross under four rounding rules side by side, in exact whole-number minor units, with the difference between summing lines and rounding the total. Not tax or accounting advice.",
      "slug": "invoice-rounding-bench",
      "url": "/tools/invoice-rounding-bench/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "accounting-sync",
        "google-sheets",
        "xero"
      ],
      "provenance": [
        {
          "label": "Rounding bench implementation",
          "url": "https://syntheticindustry.ai/tools/assets/invoice-rounding-bench.js",
          "checked": "2026-10-11",
          "claims": [
            "Quantity, unit price and tax rate are read as decimal text and scaled to whole-number integers; no floating-point value is used in any money calculation.",
            "Four rules are computed: round each line or round once on the total, each with half-up or half-even rounding of exact ties.",
            "Results are checked in the tool's test suite against an independent exact-fraction implementation over 400 seeded random invoices."
          ]
        },
        {
          "label": "Python decimal module: rounding modes",
          "url": "https://docs.python.org/3/library/decimal.html",
          "checked": "2026-10-11",
          "claims": [
            "ROUND_HALF_UP rounds to nearest with ties going away from zero.",
            "ROUND_HALF_EVEN rounds to nearest with ties going to the nearest even integer."
          ]
        }
      ],
      "related": [
        "zapier-sheets-to-xero-missing-columns",
        "guide-invoice-tax-amount-basis",
        "example-invoice-tax-rounding-reconciliation",
        "guide-sheets-invoice-value-rendering",
        "buyer-finance-manager-invoice-integration"
      ],
      "sections": [
        {
          "heading": "What it computes",
          "body": [
            "Enter one or more invoice lines (quantity, unit price and tax rate in percent), pick the number of minor-unit digits your currency has, and choose the rounding rule you want to compare against. The tool calculates net, tax and gross under four rules and shows them side by side, flags every figure that differs from your chosen rule, and reports 'line sum minus total': how far apart summing rounded lines and rounding once on the total are, in minor units (pence, cents). It also shows the exact, unrounded figures and which lines land on an exact half.",
            "Example values are loaded when the page opens so the difference is visible straight away. Replace them with your own. Nothing you enter is sent or stored."
          ],
          "items": [
            "Round each line: the line net (quantity times unit price) is rounded to a whole minor unit, tax is calculated on that rounded net and rounded again, and the invoice totals are the sums of the rounded lines.",
            "Round once on the total: exact line amounts are added up unrounded, then the invoice net and the invoice tax are each rounded once; gross is rounded net plus rounded tax.",
            "Half-up rounds an exact half away from zero (0.5 to 1, -0.5 to -1). Half-even rounds an exact half to the even neighbour (0.5 to 0, 1.5 to 2, 2.5 to 2); the two differ only on exact halves.",
            "Negative quantities or prices are treated as credit lines and round symmetrically."
          ]
        },
        {
          "heading": "A worked example you can check by hand",
          "body": [
            "Three invented lines, each quantity 1, unit price 0.03 and tax rate 20%, in a currency whose minor unit is 0.01. Each line's exact tax is 0.006, which is 0.6 of a minor unit. Rounding each line gives 1 minor unit of tax per line, so 3 in total. Adding the exact tax first gives 1.8 minor units, which rounds to 2. The two rules disagree by one minor unit of tax and so of gross. A second example: one line at 0.50 with 5% tax has exact tax of 2.5 minor units, an exact half, so half-up gives 3 and half-even gives 2.",
            "Both figures are arithmetic on invented numbers. They are not a recommendation to apply that rate or that rounding rule to any real supply."
          ],
          "items": [
            "With 500 identical copies of the first line, summing rounded lines gives 5.00 of tax and rounding the total once gives 3.00, a gap of 2.00: the difference grows with the number of lines.",
            "Which rule is right depends on your accounting system, your invoice format and the tax rules that apply to you; this tool does not decide that."
          ],
          "code": "Net  0.09 (3 x 0.03) at 20%: exact tax 0.018, exact gross 0.108\n\nRule                                Net    Tax    Gross\nRound each line, half-up            0.09   0.03   0.12\nRound each line, half-even          0.09   0.03   0.12\nRound once on the total, half-up    0.09   0.02   0.11\nRound once on the total, half-even  0.09   0.02   0.11\n\nLine sum minus total: tax +1 minor unit, gross +1 minor unit"
        },
        {
          "heading": "Assumptions and the arithmetic",
          "body": [
            "Every value is read as decimal text and scaled to a whole number: quantity, unit price and tax rate may each have up to four decimal places, up to fifteen digits before the decimal point, and the tool uses exact integer arithmetic throughout, so there is no floating-point drift. Sub-minor-unit prices such as 0.0125 are exact. Use a full stop as the decimal separator and no thousands separators: a comma is refused rather than guessed. Tax rates must be from 0 to 100 percent."
          ],
          "items": [
            "One tax rate per line; no discounts, shipping, tax-inclusive prices or currency conversion.",
            "Some systems round tax per rate group, per line on the gross amount, or only at the invoice level; check which one yours uses before relying on any column.",
            "Up to 500 lines can be calculated; the page offers 100."
          ]
        },
        {
          "heading": "What it cannot tell you",
          "body": [
            "It is not tax or accounting advice and does not know which jurisdiction, invoice type or accounting system you use. Accounting systems differ in where they round, and it cannot reproduce a specific product's behaviour. If your destination total differs from your source total, this tool can show whether a rounding rule alone could explain the gap, but a gap larger than the spread it shows has another cause, such as an amount entered as tax-inclusive that was treated as tax-exclusive. For that, see the invoice tax amount basis guide and the synthetic reconciliation example linked on this page.",
            "If an agreed column is missing from a Sheets-to-Xero mapping, the related outcome is to send every mapped Google Sheets invoice field to Xero using one disposable test row. That outcome does not include fixing tax configuration or historical invoices."
          ],
          "items": [
            "A one-unit tolerance can hide a real policy mismatch; agree the policy first.",
            "Nothing here is a quote or an offer to fix an invoice integration."
          ]
        }
      ],
      "incoming": [],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/tools/invoice-rounding-bench/",
          "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://data-ops.syntheticindustry.ai/tools/invoice-rounding-bench/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Ftools%2Finvoice-rounding-bench%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%2Fdata-ops.syntheticindustry.ai%2Ftools%2Finvoice-rounding-bench%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-invoice-tax-rounding-reconciliation",
      "type": "example",
      "title": "Synthetic invoice reconciliation: identical net lines, two different tax totals",
      "description": "Three invented small-value lines show how line-level and invoice-level tax rounding can disagree even when net values and line counts match.",
      "url": "/examples/invoice-tax-rounding-reconciliation/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "accounting-sync",
        "google-sheets",
        "xero"
      ],
      "buyer_role": "Finance owner approving source-to-destination invoice reconciliation",
      "purchase_trigger": "Every line arrives but the destination's tax and gross totals disagree with the source",
      "problem": "The integration compares grand totals without reconciling the two systems' declared tax rounding boundaries.",
      "related": [
        "guide-invoice-tax-amount-basis",
        "guide-sheets-xero-line-item-shape",
        "zapier-sheets-to-xero-missing-columns"
      ],
      "provenance": [
        {
          "label": "HMRC VAT Notice 700, invoice and retailer rounding distinctions",
          "url": "https://www.gov.uk/guidance/vat-guide-notice-700",
          "checked": "2026-10-11",
          "claims": [
            "Sections 17.5 and 17.6 distinguish invoice-trader and retailer treatments. Neither hypothetical policy below is declared applicable to the reader."
          ]
        },
        {
          "label": "Existing mapping scope excludes tax configuration",
          "url": "https://syntheticindustry.ai/services/zapier-sheets-to-xero-missing-columns/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Invented inputs, not an invoice or tax recommendation",
          "body": [
            "Use three distinct synthetic lines A, B and C, each quantity one and net amount 0.03 in an invented GBP calculation. Assume 20% solely for arithmetic and nonnegative half-up rounding to two decimals. Compare two hypothetical policies: round tax per line before summing, or sum unrounded tax and then round once. This is a worked specification, not a tested accounting connector, customer result or determination of lawful tax treatment."
          ],
          "items": [],
          "code": "line | net  | unrounded tax | half-up line tax\nA    | 0.03 | 0.006         | 0.01\nB    | 0.03 | 0.006         | 0.01\nC    | 0.03 | 0.006         | 0.01\n\nnet total                           = 0.09\npolicy L: sum rounded line tax       = 0.03; gross = 0.12\npolicy I: round total tax 0.018 once = 0.02; gross = 0.11\ndifference                          = 0.01"
        },
        {
          "heading": "Reconcile components before accepting the total",
          "body": [
            "Both hypothetical outputs retain three lines and 0.09 net. They disagree on tax and gross because their declared boundaries differ. Label each comparison with the policy, line identity and net/tax/gross components. A one-cent tolerance can hide a real policy mismatch; agreeing a tolerance does not choose the lawful policy or justify changing stored values."
          ],
          "items": [
            "The finance owner or adviser confirms the applicable policy and rates before implementation.",
            "A source formula and destination calculation must be compared under that same approved policy.",
            "Do not infer line tax from a rounded grand total or add a balancing line without agreement."
          ]
        },
        {
          "heading": "What was actually exercised",
          "body": [
            "The draft's mechanical evidence independently recomputes this arithmetic with integer rational values. That verifies the numbers only. No Sheet formula, tax engine, API, database, connector or posted invoice was exercised, and neither rounding policy is self-approved as accounting advice. HMRC guidance is UK-specific and distinguishes businesses and calculation methods; do not import this hypothetical half-up choice into a live setup."
          ],
          "items": [
            "Negative adjustments, discounts, mixed rates, exchange rates and legal invoice requirements are outside this example."
          ]
        },
        {
          "heading": "Use the existing offer only for its eligible mapping job",
          "body": [
            "If an approved net or tax field is simply missing, the existing £145 Sheets-to-Xero mapping service may fit its working trigger, five-field ceiling and authorised disposable draft. Resolving tax-policy disagreement, configuring tax, adding a calculation engine or correcting past invoices is not included. Free official guidance, your existing integrator and finance adviser are alternatives. Send invented component expectations and the missing field, never actual invoices, tax records or credentials. The price is untested; payment follows agreed checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "tool-invoice-rounding-bench",
        "collection-finance-invoice-integrity-checks",
        "guide-invoice-tax-amount-basis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/invoice-tax-rounding-reconciliation/",
          "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://data-ops.syntheticindustry.ai/examples/invoice-tax-rounding-reconciliation/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Finvoice-tax-rounding-reconciliation%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%2Fdata-ops.syntheticindustry.ai%2Fexamples%2Finvoice-tax-rounding-reconciliation%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-invoice-retry-identity-matrix",
      "type": "example",
      "title": "Synthetic invoice retry matrix: source operation, attempt and target draft are different IDs",
      "description": "Concrete made-up references specify when a retry retains one target draft and when changed contents, a second organisation or multiple matches need a separate decision.",
      "url": "/examples/invoice-retry-identity-matrix/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "accounting-sync",
        "zapier",
        "xero"
      ],
      "buyer_role": "Finance owner reviewing an integration's duplicate-prevention acceptance cases",
      "purchase_trigger": "Replaying one source row creates another unsent invoice or matches the wrong draft",
      "problem": "Transport-attempt identity is mistaken for immutable business-operation identity or the target lookup ignores organisation and content.",
      "related": [
        "guide-invoice-create-unknown-outcome",
        "buyer-finance-manager-invoice-integration",
        "zapier-sheets-to-xero-missing-columns"
      ],
      "provenance": [
        {
          "label": "IETF RFC 9110 section 9.2.2",
          "url": "https://www.rfc-editor.org/rfc/rfc9110.html",
          "checked": "2026-10-11",
          "claims": [
            "Safe automatic repetition requires known request semantics or evidence the original request was not applied; vendor-specific duplicate protection is not established."
          ]
        },
        {
          "label": "Existing mapping offer's disposable repeated-input check",
          "url": "https://syntheticindustry.ai/services/zapier-sheets-to-xero-missing-columns/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "An authored identity policy",
          "body": [
            "All labels are invented. Organisation O-A and source operation S-17 identify one immutable intended invoice creation. Attempt A-1 times out after target draft D-81 may have been created. A-2 is another transport attempt, not another invoice. Content token P means equality of the agreed business fields, not an actual checksum or vendor idempotency key. The operator must separately verify supported vendor mechanisms and safe concurrency."
          ],
          "items": [],
          "code": "organisation / operation | observed target state      | expected authored disposition\nO-A / S-17, content P     | one D-81, content P        | retain D-81; no new create\nO-A / S-17, content P     | D-81 and D-82, both P      | hold duplicate; no deletion\nO-A / S-17, content Q     | one D-81, content P        | hold content conflict\nO-A / S-17, content P     | lookup unavailable         | hold unknown\nO-A / S-17, content P     | no visible match           | unresolved until retry safety established\nO-B / S-17, content P     | D-81 exists only in O-A     | never reuse O-A's draft"
        },
        {
          "heading": "A changed source is not silently a retry",
          "body": [
            "Under this example's immutable-operation rule, editing S-17 from P to Q needs a separately authorised correction decision; generating a fresh attempt ID must not bypass that rule. Two source operations with equal amounts are not necessarily duplicates. A row number that changes after sorting is not a proven stable operation identity. A real integration needs a durable documented identity contract, not these made-up strings alone."
          ],
          "items": [
            "Test changed contents and cross-organisation matching separately from repeating an identical input.",
            "No draft may be deleted, sent or posted merely to make the matrix pass."
          ]
        },
        {
          "heading": "Specification, not a tested connector",
          "body": [
            "The matrix is an authored acceptance specification. No provider lookup, idempotency key, concurrency mechanism or recovery process has been executed. The HTTP source supports the caution about repeating uncertain writes; it does not validate this policy or establish a particular vendor's response. A real test would retain target identities, counts and dispositions on an authorised isolated route."
          ],
          "items": [
            "An eventual zero-match lookup is not automatically authoritative evidence that no write occurred.",
            "No invented event here is a customer enquiry, invoice or payment."
          ]
        },
        {
          "heading": "A narrow contextual priced route",
          "body": [
            "Use this matrix to ask the existing operator how their duplicate rule works. The £145 Sheets-to-Xero offer is still a five-field repair with one disposable row and agreed repeated-input checks, not a reconciliation or idempotency subsystem. Request it only if that mapping scope fits; recovery, historical cleanup and new architecture require separate agreement. Send invented identities and expected dispositions, not customer references, invoices or keys. The price is untested and payment follows the agreed passing checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "collection-finance-invoice-integrity-checks",
        "guide-invoice-create-unknown-outcome"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/examples/invoice-retry-identity-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://data-ops.syntheticindustry.ai/examples/invoice-retry-identity-matrix/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fexamples%2Finvoice-retry-identity-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%2Fdata-ops.syntheticindustry.ai%2Fexamples%2Finvoice-retry-identity-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": "collection-finance-invoice-integrity-checks",
      "type": "category",
      "title": "Invoice integration review: verify shape, representation, tax basis and repeat safety",
      "description": "An ordered review worksheet helps a finance owner stop at the first broken contract before requesting a bounded existing mapping repair.",
      "url": "/collections/finance-invoice-integrity-checks/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "accounting-sync",
        "google-sheets",
        "zapier",
        "xero"
      ],
      "buyer_role": "Finance owner preparing a low-trust source-to-draft acceptance request",
      "purchase_trigger": "An automation runs but its invoice cannot be accepted without manual reconstruction",
      "problem": "One successful workflow or matching grand total substitutes for separate checks of invoice identity, fields and side effects.",
      "related": [
        "guide-sheets-xero-line-item-shape",
        "guide-sheets-invoice-value-rendering",
        "guide-invoice-tax-amount-basis",
        "example-invoice-tax-rounding-reconciliation",
        "guide-invoice-create-unknown-outcome",
        "example-invoice-retry-identity-matrix",
        "buyer-finance-manager-invoice-integration",
        "zapier-sheets-to-xero-missing-columns"
      ],
      "provenance": [
        {
          "label": "Google Sheets value representations",
          "url": "https://developers.google.com/sheets/api/reference/rest/v4/ValueRenderOption",
          "checked": "2026-10-11",
          "claims": [
            "Formatted and unformatted outputs can represent the same cell differently."
          ]
        },
        {
          "label": "IETF RFC 9110 retry boundaries",
          "url": "https://www.rfc-editor.org/rfc/rfc9110.html",
          "checked": "2026-10-11",
          "claims": [
            "A lost response does not itself justify automatically repeating a non-idempotent request."
          ]
        },
        {
          "label": "Existing bounded mapping price and exclusions",
          "url": "https://syntheticindustry.ai/services/zapier-sheets-to-xero-missing-columns/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Use the worksheet with invented data",
          "body": [
            "This sequence is authored review advice, not a vendor integration recipe or evidence of demand. Name one intended organisation and unsent synthetic draft, with the expected invoice and line counts. Stop at the first disagreement; fixing a later total cannot correct a wrongly grouped or assigned invoice."
          ],
          "items": [
            "1. Shape: compare invoice count and each line's description, quantity and own amount; reuse the existing line-shape guide.",
            "2. Representation: compare the connector's captured date and amount types with destination requirements.",
            "3. Basis: finance approves currency, net/gross meaning and tax treatment before any mapping change.",
            "4. Components: reconcile net, tax and gross under one approved rounding policy.",
            "5. Identity: distinguish source operation, attempt and target draft; specify unknown and repeated-input outcomes."
          ]
        },
        {
          "heading": "Keep a result for each boundary",
          "body": [
            "For each worksheet row retain an invented input, expected result, observed result when actually tested, and the responsible approver. Until a test is executed, observed stays unverified. A missing mandatory field must produce the agreed exception; a timeout must not silently become another creation. The worked examples supply specifications, not passing integration evidence."
          ],
          "items": [
            "Do not require private invoices or customer data to prepare first-contact cases.",
            "Inspect an authorised disposable draft; a test button may write connected records.",
            "The organisation holder controls live posting and sending."
          ]
        },
        {
          "heading": "Choose a correction rather than a new accounting package",
          "body": [
            "If the issue is a stale mapping within an already-working five-field route, the existing £145 Sheets-to-Xero offer is relevant after fit confirmation. Variable grouping, a failed trigger, tax setup, historical corrections, new retry architecture and live sending are not included. Ask the existing maintainer or vendor support first when their documented configuration resolves the problem. Ask a qualified finance adviser for undecided tax policy."
          ],
          "items": [
            "This collection is not a new paid bundle and does not make the six linked checks six purchasable repairs.",
            "QuickBooks users may reuse the business questions, but the Xero offer does not become a QuickBooks package."
          ]
        },
        {
          "heading": "A scope-bearing enquiry",
          "body": [
            "Send invented headers and expected/actual results for the first failing boundary, confirm the working trigger and disposable test route, and identify the finance approver and budget holder. State your response to £145 only if that existing scope fits. No source code, financial exports, credentials or invitations initially. The price is an untested proposal; an enquiry creates no booking, account access or financial authority and payment follows agreed checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/collections/finance-invoice-integrity-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://data-ops.syntheticindustry.ai/collections/finance-invoice-integrity-checks/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fcollections%2Ffinance-invoice-integrity-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%2Fdata-ops.syntheticindustry.ai%2Fcollections%2Ffinance-invoice-integrity-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."
      }
    },
    {
      "id": "guide-sheets-invoice-value-rendering",
      "type": "guide",
      "title": "Invoice values look right in Sheets but arrive as currency text or a date number",
      "description": "Separate a spreadsheet's displayed currency and date from the values a connector reads, then agree the destination types before repairing a mapping.",
      "url": "/guides/sheets-invoice-value-rendering/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "google-sheets",
        "zapier",
        "xero"
      ],
      "buyer_role": "Finance owner approving the types of mapped invoice fields",
      "purchase_trigger": "A populated source cell reaches an invoice action in an unexpected numeric or textual representation",
      "problem": "Display formatting, formula text and evaluated values are mistaken for the same connector input.",
      "related": [
        "guide-zapier-field-mapping",
        "guide-sheets-xero-line-item-shape",
        "guide-invoice-tax-amount-basis",
        "zapier-sheets-to-xero-missing-columns"
      ],
      "provenance": [
        {
          "label": "Google Sheets API value render options",
          "url": "https://developers.google.com/sheets/api/reference/rest/v4/ValueRenderOption",
          "checked": "2026-10-11",
          "claims": [
            "Formatted values apply spreadsheet locale and cell formatting; unformatted values evaluate formulas without formatting; FORMULA returns formula text."
          ]
        },
        {
          "label": "Google Sheets values.get defaults",
          "url": "https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get",
          "checked": "2026-10-11",
          "claims": [
            "valueRenderOption defaults to FORMATTED_VALUE; dateTimeRenderOption is ignored with FORMATTED_VALUE."
          ]
        },
        {
          "label": "Google Sheets number and date formats",
          "url": "https://developers.google.com/sheets/api/guides/formats",
          "checked": "2026-10-11",
          "claims": [
            "Dates and times have serial-number representations; locale influences rendering. A currency format is presentation, not currency conversion."
          ]
        },
        {
          "label": "Existing five-field Sheets-to-Xero mapping offer",
          "url": "https://syntheticindustry.ai/services/zapier-sheets-to-xero-missing-columns/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "A visible cell is only one representation",
          "body": [
            "With invented data, a numeric 1234.50 may display with a currency symbol and grouping characters. A date can be displayed as calendar text while the underlying value is a serial number. Record the visible cell, the connector's captured value and type, and the action's required type separately. This is not the missing-header problem: the value exists but its representation may not fit the destination."
          ],
          "items": [
            "Record spreadsheet locale, cell format and the intended invoice currency separately.",
            "Distinguish a formula such as =A1 from its evaluated result.",
            "Do not parse an ambiguous date such as 03/04/2026 by guessing its locale."
          ]
        },
        {
          "heading": "The API explains the distinction, not your Zap's controls",
          "body": [
            "Google's API offers formatted, unformatted and formula representations. Its values.get method defaults to formatted output, and the date-time option has no effect in that mode. Sheets date serials count from December 30, 1899 and can contain a fractional day. These are documented API behaviours, not a claim that the current Zapier trigger exposes an option with the same name or uses a particular mode. Inspect the actual captured sample through the authorised operator; do not change a live connector based on an API recipe."
          ],
          "items": [
            "The connector version and selected action must be verified separately.",
            "A currency symbol does not establish the currency code or an exchange rate.",
            "If conversion is necessary, agree the exact date and monetary input contract first."
          ]
        },
        {
          "heading": "A useful acceptance case changes the display, not the business meaning",
          "body": [
            "Use invented amounts and an unambiguous invoice date on an authorised disposable route. Declare whether changing only cell presentation should leave the destination amount and date unchanged. Compare the mapped amount, date and currency after each agreed presentation variant. If a serial or formatted string is unsupported, require a visible exception rather than silent zero, today's date or a guessed conversion. These are proposed checks; no Sheet, connector or invoice was exercised for this draft."
          ],
          "items": [
            "Inspect destination types and values, not just a screenshot that looks similar.",
            "Keep a missing-value case distinct from a wrong-type case."
          ]
        },
        {
          "heading": "DIY first, and preserve the £145 boundary",
          "body": [
            "An authorised maintainer may resolve the issue by inspecting the trigger sample and correcting an existing mapping; Google documentation is free to read. The existing £145 Sheets-to-Xero offer concerns an already-working trigger, up to five named fields and one disposable draft. It is a contextual route, not a promise to build a new date parser, currency converter or variable line-item transformation at that price. Tax setup, historical corrections and sending invoices are excluded. Send invented cell values, displayed forms and expected destination types initially, not financial exports, code, credentials or invitations. The price is untested; work requires agreed scope and payment follows passing checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "tool-invoice-rounding-bench",
        "collection-finance-invoice-integrity-checks",
        "guide-invoice-tax-amount-basis"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/sheets-invoice-value-rendering/",
          "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://data-ops.syntheticindustry.ai/guides/sheets-invoice-value-rendering/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Fsheets-invoice-value-rendering%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%2Fdata-ops.syntheticindustry.ai%2Fguides%2Fsheets-invoice-value-rendering%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-invoice-tax-amount-basis",
      "type": "guide",
      "title": "An invoice integration adds tax twice: agree whether each amount is net or gross",
      "description": "Name the tax basis of each mapped line and the approved tax treatment before mistaking a populated amount field for a correct invoice.",
      "url": "/guides/invoice-tax-amount-basis/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "google-sheets",
        "xero",
        "accounting-sync"
      ],
      "buyer_role": "Finance owner responsible for invoice amount and tax-policy sign-off",
      "purchase_trigger": "The destination total differs even though all source amounts were populated",
      "problem": "A tax-inclusive amount is treated as tax-exclusive, or tax calculation policy is silently changed at a mapping boundary.",
      "related": [
        "example-invoice-tax-rounding-reconciliation",
        "guide-sheets-invoice-value-rendering",
        "buyer-finance-manager-invoice-integration",
        "zapier-sheets-to-xero-missing-columns"
      ],
      "provenance": [
        {
          "label": "HMRC VAT Notice 700, sections 17.5 and 17.6",
          "url": "https://www.gov.uk/guidance/vat-guide-notice-700",
          "checked": "2026-10-11",
          "claims": [
            "Invoice-trader rounding concessions and retailer treatment differ; line-calculation methods require consistency. This is UK-specific guidance, not a universal rounding rule or a determination of a reader's tax treatment."
          ]
        },
        {
          "label": "Google Sheets formatting is presentation",
          "url": "https://developers.google.com/sheets/api/guides/formats",
          "checked": "2026-10-11",
          "claims": [
            "Number patterns and spreadsheet locale affect rendered values; they do not choose business tax policy."
          ]
        },
        {
          "label": "Existing mapping repair excludes Xero tax configuration",
          "url": "https://syntheticindustry.ai/services/zapier-sheets-to-xero-missing-columns/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Put a basis beside the amount",
          "body": [
            "For each invented line, name currency, quantity, unit amount, whether the unit amount includes tax, the approved tax treatment and any permitted discount. A field labelled amount is insufficient. Formatting it to two decimals does not tell the destination whether tax is included. The finance owner or their qualified adviser supplies the applicable treatment; this guide does not decide rates, exemptions or tax liability."
          ],
          "items": [
            "Separate monetary basis from which account or tax identifier is mapped.",
            "Do not assume a blank tax field means exempt or zero-rated.",
            "The actual connector's supported fields must be verified; no Xero or QuickBooks action configuration is prescribed here."
          ]
        },
        {
          "heading": "A synthetic double-tax counterexample",
          "body": [
            "Assume solely for invented arithmetic a net amount of 20.00 and a 20% rate. The declared result is 4.00 tax and 24.00 gross. If 24.00 is passed as a net amount and another 20% is added, the result becomes 28.80. The 4.80 difference is a basis mistake, not merely a penny-rounding issue. These numbers are not a recommendation to apply that rate to any real supply."
          ],
          "items": [
            "Assert the net, tax and gross components, not only the grand total.",
            "If the approved basis is unknown, hold the proposed draft instead of trying both settings on real invoices."
          ]
        },
        {
          "heading": "Rounding and tax setup belong to an explicit policy",
          "body": [
            "HMRC's UK guidance distinguishes invoice traders from retailers and describes different rounding treatments. It cannot safely be reduced to always round down or always round each line. Agree the policy that applies to the business, then record where rounding occurs and how the destination applies it. The related synthetic example exposes a line-versus-invoice difference without choosing a legally applicable policy."
          ],
          "items": [
            "Do not adjust a final total merely to hide disagreeing component amounts.",
            "No live invoice, tax configuration or financial correction has been performed."
          ]
        },
        {
          "heading": "Mapping repair is not tax advice",
          "body": [
            "Use the existing maintainer, vendor help or your finance adviser when the policy or account setup is unresolved. A missing field under an already approved treatment may be discussed through the existing £145 five-field Sheets-to-Xero mapping offer, only with its working trigger and authorised disposable-draft route. Fixing tax configuration, deciding tax policy, custom arithmetic, historical invoices and live sending are outside that offer. Send invented net/tax/gross expectations and the missing mapping, not tax returns, customer details or credentials. Scope must be confirmed; the price is untested and payment follows agreed checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "tool-invoice-rounding-bench",
        "example-invoice-tax-rounding-reconciliation",
        "collection-finance-invoice-integrity-checks",
        "guide-sheets-invoice-value-rendering"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/invoice-tax-amount-basis/",
          "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://data-ops.syntheticindustry.ai/guides/invoice-tax-amount-basis/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Finvoice-tax-amount-basis%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%2Fdata-ops.syntheticindustry.ai%2Fguides%2Finvoice-tax-amount-basis%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-invoice-create-unknown-outcome",
      "type": "guide",
      "title": "Invoice creation timed out: reconcile the unknown result before retrying",
      "description": "Distinguish a confirmed rejected creation from a lost response after a possible write, and define zero, one and conflicting-match dispositions before a replay.",
      "url": "/guides/invoice-create-unknown-outcome/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "accounting-sync",
        "zapier",
        "xero"
      ],
      "buyer_role": "Finance owner deciding whether an accounting automation may retry",
      "purchase_trigger": "An action reports a timeout and nobody knows whether the unsent invoice already exists",
      "problem": "A failed transport response is treated as proof that invoice creation had no effect.",
      "related": [
        "example-invoice-retry-identity-matrix",
        "buyer-finance-manager-invoice-integration",
        "guide-zapier-field-mapping",
        "zapier-sheets-to-xero-missing-columns"
      ],
      "provenance": [
        {
          "label": "IETF RFC 9110 section 9.2.2: retry semantics",
          "url": "https://www.rfc-editor.org/rfc/rfc9110.html",
          "checked": "2026-10-11",
          "claims": [
            "A client should not automatically retry a non-idempotent method without knowing its semantics are idempotent or detecting that the original request was never applied. This does not establish any accounting vendor's idempotency support."
          ]
        },
        {
          "label": "Existing mapping offer and repeated-input acceptance",
          "url": "https://syntheticindustry.ai/services/zapier-sheets-to-xero-missing-columns/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Unknown is a separate outcome",
          "body": [
            "A timeout can occur before a write or after a write whose response was lost. Preserve the minimal synthetic source reference, target organisation, attempted operation and result state. Do not replace unknown with failed-and-empty merely because the workflow is red. RFC 9110 explains why automatic retries of non-idempotent requests need more evidence; it does not promise a safe replay facility in Xero, QuickBooks or Zapier."
          ],
          "items": [
            "A new attempt identifier is not a new business invoice.",
            "A human-readable invoice number alone is not proven globally unique.",
            "Do not infer that switching a creation request to PUT makes the business operation safe."
          ]
        },
        {
          "heading": "Specify reconciliation before another create",
          "body": [
            "Under an explicitly authored test policy, one matching target draft with the agreed source reference and expected contents means retain that target, not create another. More than one match, or one match with different contents, is an exception for the authorised finance owner. Zero visible matches is not automatically permission to retry: delayed visibility or another in-flight attempt can still exist. The implementer must establish the actual vendor's lookup, duplicate-prevention and concurrency semantics separately."
          ],
          "items": [
            "Keep organisation and immutable source-operation identity together.",
            "Record confirmed rejected, confirmed created and unknown separately.",
            "A read-then-create sequence alone is not concurrency protection."
          ]
        },
        {
          "heading": "Acceptance includes the lost-response branch",
          "body": [
            "An isolated synthetic specification simulates creation followed by loss of the response. Its repeated operation must retain one draft or enter the approved unresolved state, never silently create a second draft. Also specify a confirmed rejection and conflicting-target case. The related matrix provides concrete identities and expected dispositions. No API, replay, target lookup, concurrent worker or invoice has been run for this draft."
          ],
          "items": [
            "Inspect target count and identity beside the workflow result.",
            "Never bulk replay historical invoices as diagnosis.",
            "Deleting a duplicate or changing a posted document is a separate financial action."
          ]
        },
        {
          "heading": "The £145 offer is a mapping route, not an idempotency redesign",
          "body": [
            "An authorised operator may investigate existing run and draft state using vendor support, with no new paid integration required. The existing £145 mapping repair includes an agreed repeated-input check on one disposable row, not a new reconciliation store, queue, retry architecture or historical cleanup. Enquire there only for the eligible five-field mapping problem with a working trigger and a safe draft test; unknown-state recovery or missing duplicate safeguards need separately agreed scope. Send an invented operation identity and expected result initially, not real invoice exports, source code or keys. The price remains untested; agreement precedes access and payment follows checks and sign-off."
          ],
          "items": []
        }
      ],
      "incoming": [
        "example-invoice-retry-identity-matrix",
        "collection-finance-invoice-integrity-checks"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/guides/invoice-create-unknown-outcome/",
          "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://data-ops.syntheticindustry.ai/guides/invoice-create-unknown-outcome/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fguides%2Finvoice-create-unknown-outcome%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%2Fdata-ops.syntheticindustry.ai%2Fguides%2Finvoice-create-unknown-outcome%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",
        "buyer-distributor-supplier-feed-owner"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-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://data-ops.syntheticindustry.ai/examples/supplier-key-collision-matrix/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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",
        "buyer-distributor-supplier-feed-owner"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-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://data-ops.syntheticindustry.ai/examples/supplier-update-presence-contract/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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",
        "buyer-distributor-supplier-feed-owner"
      ],
      "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",
        "buyer-distributor-supplier-feed-owner"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-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://data-ops.syntheticindustry.ai/examples/supplier-pack-price-calculation/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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",
        "buyer-distributor-supplier-feed-owner"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-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://data-ops.syntheticindustry.ai/examples/supplier-feed-version-disposition/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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://data-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://data-ops.syntheticindustry.ai/guides/supplier-sku-text-identity/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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://data-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://data-ops.syntheticindustry.ai/guides/supplier-key-namespace/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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",
        "buyer-distributor-supplier-feed-owner"
      ],
      "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://data-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://data-ops.syntheticindustry.ai/guides/supplier-conflicting-duplicate-rows/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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://data-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://data-ops.syntheticindustry.ai/guides/supplier-blank-price-update/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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",
        "buyer-distributor-supplier-feed-owner"
      ],
      "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://data-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://data-ops.syntheticindustry.ai/guides/supplier-snapshot-versus-delta/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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",
        "buyer-distributor-supplier-feed-owner"
      ],
      "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://data-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://data-ops.syntheticindustry.ai/guides/supplier-pack-versus-unit-price/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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://data-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://data-ops.syntheticindustry.ai/guides/supplier-feed-freshness-order/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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://data-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://data-ops.syntheticindustry.ai/guides/supplier-feed-header-drift/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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": "buyer-distributor-supplier-feed-owner",
      "type": "buyer",
      "title": "For a distributor's operations owner: stop supplier-feed mistakes without a new inventory system",
      "description": "Name who approves product matching, units and feed exceptions, then request one testable local repair or one small review interaction in the application you already use.",
      "url": "/buyers/distributor-supplier-feed-owner/",
      "version": 1,
      "lifecycle": "candidate",
      "updated": "2026-10-11",
      "platforms": [
        "supplier-feeds",
        "postgresql"
      ],
      "buyer_role": "Operations or purchasing owner at a small distributor with an existing internal web application",
      "purchase_trigger": "Manual checking follows each supplier file because the app cannot be trusted to preserve the intended stock and price state",
      "problem": "An accountable business owner needs a bounded application improvement, but source policies and acceptance criteria have not been separated from live imports.",
      "related": [
        "collection-supplier-feed-import-checks",
        "example-supplier-key-collision-matrix",
        "example-supplier-update-presence-contract",
        "example-supplier-pack-price-calculation",
        "example-supplier-feed-version-disposition"
      ],
      "provenance": [
        {
          "label": "W3C tabular model: keys, cells and explicit units metadata",
          "url": "https://www.w3.org/TR/tabular-data-model/",
          "checked": "2026-10-11",
          "claims": [
            "Tabular structures and metadata can express keys and units but do not decide a supplier's commercial semantics."
          ]
        },
        {
          "label": "Current local repair eligibility and price",
          "url": "https://syntheticindustry.ai/services/fix-one-bug-with-regression-test/",
          "checked": "2026-10-11"
        },
        {
          "label": "Current preview-feature eligibility and price",
          "url": "https://syntheticindustry.ai/services/ship-one-feature-with-running-preview/",
          "checked": "2026-10-11"
        }
      ],
      "sections": [
        {
          "heading": "Describe the failed business result",
          "body": [
            "Use one invented case: the wrong supplier's item changed, a blank erased a price, a carton became one item, or an older feed replaced a newer one. Say what was stored before and what should remain afterward. A request to automate all purchasing is too broad for a small repair; a specific failed decision can be tested without handing over live stock or prices."
          ],
          "items": [
            "Document current manual review and exceptions without inventing labour savings.",
            "Name the application and whether it can run on synthetic inputs.",
            "One defect or one new review interaction is the initial unit of scope, not a promise to replace your inventory system."
          ]
        },
        {
          "heading": "Name the policy owners",
          "body": [
            "Purchasing approves product equivalence, pack units and allowed price changes. The source owner defines full versus delta coverage and source versioning. The application owner authorises its test and code route. An importer cannot invent these policies safely. Unknown rules belong in an exception path until the responsible owner decides them."
          ],
          "items": [
            "Do not turn missing source information into a zero price or unavailable item by guesswork.",
            "Accounts, supplier terms and live publication authority remain with their holders.",
            "No request for an owner without a developer to operate a database or share a password is implied."
          ]
        },
        {
          "heading": "Choose between repair and preview",
          "body": [
            "If existing logic gives one wrong deterministic result, a failing-then-passing regression may define the repair. If users lack one bounded way to inspect proposed changes or exceptions, a feature preview may define the new interaction. The existing offers still require a safe authorised code handoff and, for a feature, an existing isolated private preview. If nobody can approve or merge the change, agree the delivery route before accepting work; do not assume an account invitation solves it."
          ],
          "items": [
            "A live importer that can be reproduced only with production credentials is not eligible for the local bug offer.",
            "Supplier retrieval, production corrections, new accounts and real purchasing actions need separate authority and scope."
          ]
        },
        {
          "heading": "Start with a low-trust priced enquiry",
          "body": [
            "Describe the invented before/input/expected-after case, stack, policy owner and desired outcome. The current bug repair starts from £295 after bounded reproduction and a fixed quote; the current one-feature preview starts from £750 after agreeing criteria, existing private preview and two revision rounds. Both prices are untested proposals. An enquiry does not book work, authorise an import or start payment; payment follows agreed checks and sign-off. No source code, private price lists, supplier access or customer data in first contact."
          ],
          "items": [
            "Documentation and this buyer hypothesis do not establish paying demand, qualified arrivals or client delivery.",
            "If safe code or preview access cannot be resolved, keep work with the existing authorised operator rather than bypassing that boundary."
          ]
        }
      ],
      "incoming": [
        "buyer-feed-operations-manager-supplier-file-delivery",
        "example-supplier-pack-price-calculation",
        "guide-supplier-conflicting-duplicate-rows",
        "guide-supplier-snapshot-versus-delta",
        "guide-supplier-pack-versus-unit-price",
        "collection-supplier-feed-import-checks"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-ops.syntheticindustry.ai/api/enquiries",
        "media_type": "application/json",
        "required": [
          "contact",
          "need",
          "idempotency_key",
          "website"
        ],
        "fields": {
          "outcome": "custom-outcome",
          "source": "/buyers/distributor-supplier-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://data-ops.syntheticindustry.ai/buyers/distributor-supplier-feed-owner/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-ops.syntheticindustry.ai/request/?outcome=custom-outcome&source=%2Fbuyers%2Fdistributor-supplier-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%2Fdata-ops.syntheticindustry.ai%2Fbuyers%2Fdistributor-supplier-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-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",
        "buyer-distributor-supplier-feed-owner"
      ],
      "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",
        "buyer-distributor-supplier-feed-owner"
      ],
      "request": {
        "method": "POST",
        "endpoint": "https://data-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://data-ops.syntheticindustry.ai/collections/supplier-feed-import-checks/",
          "SI-Ref": "unknown"
        },
        "url": "https://data-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%2Fdata-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."
      }
    }
  ]
}
