COGS Onboarding Worksheet — MIZOKI Signal for Shopify (P1)
Status: v1.0 (2026-08-11) · P1 workstream zero (INTEGRATION PROMPT v2.3 F6) ·
For ERP-less merchants; canon: docs/product/SIGNAL_SHOPIFY_MASTER_v4.md §2.1 (cost side)
and §2.5 (NCM-v1 terms). Machine template: cogs_worksheet_template.csv.
Why this exists
NCM-v1 (services/measurement-rails/ncm_v1.py) refuses to guess costs: an order with no
COGS components or an unreconciled bundle is rejected, not estimated. This worksheet is
how a merchant without an ERP supplies the per-variant truth once, so every order after that
computes honestly. Bundle/kit distortion is a known Shopify analytics failure mode — the
worksheet forces bundle decomposition up front.
How to fill it (one row per sellable variant)
| Column | NCM-v1 term | What to enter | Honest default when unknown |
|---|---|---|---|
variant_id |
— | Shopify variant ID (the component variant, not the bundle listing) | required — no default |
sku |
— | Your SKU for the variant | required |
landed_unit_cogs |
COGS | Supplier cost + inbound freight + duty, per unit, in store currency | leave blank — the row is excluded and flagged, never guessed |
is_bundle |
COGS | true if this listing sells a kit of other variants |
false |
bundle_components |
COGS | For bundles: component_variant_id:qty pairs separated by ; (e.g. 123:2;456:1). Component rows must exist with their own landed_unit_cogs. |
required when is_bundle |
pick_pack_cost |
F | 3PL pick/pack fee per unit (your 3PL rate card) | fulfillment default row (below) |
dimensional_surcharge |
F | Oversize/dimensional shipping surcharge per unit, if any | 0 |
return_rate_pct |
E[RL] | Trailing 12-month return rate for the variant (or category) in percent | category default row, labeled |
return_unit_cost |
E[RL] | Freight-in + inspection labor + restock or markdown loss per returned unit | category default row, labeled |
notes |
— | Free text (supplier, season, effective date) | empty |
Store-level defaults sheet (second block of the CSV): payment/platform fee percent (S), default pick/pack, category-level return defaults. Store-level promo cost (P) is not on this sheet — promos pro-rate from Shopify discount data per order.
Rules the worksheet enforces (same rules the code enforces)
- Bundles decompose or are rejected. Every
bundle_componentsvariant must have its own costed row; quantities must reconcile to the bundle quantity. - Blank beats guessed. A blank
landed_unit_cogsexcludes the variant from NCM and shows up in the coverage report; an invented number would silently poison every margin figure downstream. - Currency is the store currency everywhere. No mixed-currency rows.
- Effective-dated updates, never edits-in-place once live: append a new row with a
later effective date in
notes; history stays reconstructable. - Values entered here are merchant-confidential inputs — they feed NCM-v1 computation and never leave the tenant boundary (fleet-integrity rules: no cross-merchant visibility).
What happens next (P1 flow)
Worksheet → validated import (rejects rule violations with row-level reasons) → per-variant
cost table → OrderEconomics per order → NCM-v1. The validated-import step is built
(P1 build plan item C1): services/measurement-rails/cogs_import.py parses exactly this
CSV shape — its suite parses the repo template file directly, so a change to either side
fails the build instead of drifting silently.