fix(products): serialize Variant Position explicitly — INV-12 round-trip bug
ci / check (push) Has been cancelled
ci / check (pull_request) Has been cancelled

A stored variant position is a CatalogVariant attribute, not a fields{} entry,
so the serializer emitted an empty Variant Position cell — which re-imports as
'reset to file order'. A non-sequential stored position (a merchant can import
explicit positions) then round-tripped to a spurious update, violating INV-12.
Emit str(variant.position) explicitly (like _write_image). The property-test
generator now assigns non-sequential positions to lock the regression, plus a
targeted test. Also wires isExportEnabled into ProductsPage (was dead code).
Both caught by the final code review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 22:22:11 -07:00
parent 6f22c8b146
commit af72299a57
3 changed files with 39 additions and 5 deletions
@@ -1,5 +1,5 @@
// Products page (SD-0002 §5.2) — the catalog's home: where imports start and history
// lives. SLICE-5: export is disabled (SLICE-6 ships it); the browsable list is #14's.
// Products page (SD-0002 §5.2) — the catalog's home: where imports start, exports
// download, and history lives. SLICE-6 ships the export menu; the browsable list is #14's.
import { useEffect, useState } from "react";
import {
dialectLabel,
@@ -11,6 +11,7 @@ import {
type RunSummary,
} from "../../productsApi";
import { Banner } from "../../ui/kit";
import { isExportEnabled } from "./exportMenu";
const STATUS_LABELS: Record<string, string> = {
applying: "Importing…",
@@ -56,7 +57,7 @@ export default function ProductsPage() {
);
}
const empty = summary.product_count === 0;
const empty = !isExportEnabled(summary.product_count);
return (
<div className="products">
<header className="products__header">