SLICE-8: Shopify dialect — detect/map Shopify export at the codec boundary + DOC-2/3 (SD-0002 §7.2) #32

Merged
ben.stull merged 11 commits from slice-8-shopify-dialect into main 2026-06-12 09:37:38 +00:00
Owner

SLICE-8 — Shopify dialect + public format docs (SD-0002 §7.2)

Closes Products story #13. Completes PUC-6 (a Shopify export imports directly) and PUC-11 (learning the format).

What ships

  • Header-set dialect detection (detect_dialect / dialect_shopify.is_shopify_header): a file is shopify iff it carries a Shopify-only signature column and no canonical-distinctive column. The canonical veto keeps detection conservative (under-detection warns; over-detection corrupts) — never misparses (§7.4).
  • Shopify→canonical mapping at the codec boundary (INV-17): renames (Body (HTML)Description, Product CategoryGoogle Product Category, Cost per itemVariant Cost, Variant GramsVariant Weight+synth unit g), direct passthroughs, and Shopify columns with no canonical home surfaced as the not-imported warning. Two name-collision overrides: Shopify free-text Type (canonical Type is structural) and Variant Weight Unit (superseded by the grams transform). Exhaustive mapping pinned as a fixture (§6.5.1).
  • Preview UI: "Shopify product CSV — mapped" label + the existing not-imported columns band; format help links the column reference.
  • DOC-2 — column reference served at GET /api/products/columns.md.
  • DOC-3sample.csv confirmed final (variants + images, parses clean canonical).
  • DOC-4 — dialect-adapter dev notes.

Tests

  • Unit: detection (incl. conservative veto), exhaustive mapping fixture, grams transform + clear, INV-10 over a partial Shopify import.
  • E2E: e2e_import_shopify_dialect (unmodified Shopify export → mapped banner + not-imported band → confirm → run completes).
  • Full gate green: import-linter + backend pytest + frontend build/vitest; Playwright 8/8.

Review hardening (adversarial pass)

A canonical file carrying a stray Shopify-signature name (e.g. SEO Title) previously misdetected as Shopify and silently dropped Type / corrupted the weight unit (kg→g). The canonical-distinctive veto closes that, the dual-named shadow (Body (HTML)+Description), and the stale-unit-on-clear case.

Version bump v0.7.0 → v0.8.0.

🤖 Generated with Claude Code

## SLICE-8 — Shopify dialect + public format docs (SD-0002 §7.2) Closes Products story #13. Completes **PUC-6** (a Shopify export imports directly) and **PUC-11** (learning the format). ### What ships - **Header-set dialect detection** (`detect_dialect` / `dialect_shopify.is_shopify_header`): a file is `shopify` iff it carries a Shopify-only *signature* column **and** no canonical-distinctive column. The canonical veto keeps detection conservative (under-detection warns; over-detection corrupts) — never misparses (§7.4). - **Shopify→canonical mapping at the codec boundary** (INV-17): renames (`Body (HTML)`→`Description`, `Product Category`→`Google Product Category`, `Cost per item`→`Variant Cost`, `Variant Grams`→`Variant Weight`+synth unit `g`), direct passthroughs, and Shopify columns with no canonical home surfaced as the not-imported warning. Two name-collision overrides: Shopify free-text `Type` (canonical `Type` is structural) and `Variant Weight Unit` (superseded by the grams transform). Exhaustive mapping pinned as a fixture (§6.5.1). - **Preview UI**: "Shopify product CSV — mapped" label + the existing not-imported columns band; format help links the column reference. - **DOC-2** — column reference served at `GET /api/products/columns.md`. - **DOC-3** — `sample.csv` confirmed final (variants + images, parses clean canonical). - **DOC-4** — dialect-adapter dev notes. ### Tests - Unit: detection (incl. conservative veto), exhaustive mapping fixture, grams transform + clear, INV-10 over a partial Shopify import. - E2E: `e2e_import_shopify_dialect` (unmodified Shopify export → mapped banner + not-imported band → confirm → run completes). - Full gate green: import-linter + backend pytest + frontend build/vitest; Playwright 8/8. ### Review hardening (adversarial pass) A canonical file carrying a stray Shopify-signature name (e.g. `SEO Title`) previously misdetected as Shopify and silently dropped `Type` / corrupted the weight unit (kg→g). The canonical-distinctive veto closes that, the dual-named shadow (`Body (HTML)`+`Description`), and the stale-unit-on-clear case. Version bump v0.7.0 → **v0.8.0**. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
ben.stull added 11 commits 2026-06-12 09:37:21 +00:00
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(products): conservative dialect detection — canonical-distinctive columns veto Shopify (SLICE-8 review)
ci / check (push) Has been cancelled
ci / check (pull_request) Has been cancelled
a851d3587c
Addresses adversarial-review findings: a canonical file carrying a stray
Shopify-signature name (e.g. SEO Title) no longer misdetects as Shopify and
silently drops canonical Type / corrupts the weight unit (kg->g). A
canonical-distinctive column (Description/Variant Cost/Variant Weight/Google
Product Category/Variant Volume/Tax ID/Position) now vetoes detection, so
detection leans conservative (under-detection warns; over-detection corrupts).
Also closes the dual-named-column shadow (Body (HTML)+Description) and the
stale-weight-unit-on-clear case. Tests cover all three.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ben.stull merged commit e2d8b5caae into main 2026-06-12 09:37:38 +00:00
ben.stull deleted branch slice-8-shopify-dialect 2026-06-12 09:37:38 +00:00
Sign in to join this conversation.