DB-free host-agnostic helpers: image_url() builds the canonical hosted
Image Src for a fetched image; parse_image_id() recognizes one on re-import
via path-parse so exports round-trip across localhost/PPE/rebrand (INV-12).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
A blank Variant Position cell previewed position->null and aborted the
confirm transaction (variant.position is NOT NULL). Resolve the clear to
the variant's file order at diff time so preview and apply stay in
lockstep; carry file_order on VariantPlan instead of an identity-keyed
map; release the read snapshot before PreviewStale/NothingToApply.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A Variant Position column previously produced a spurious update with a
false before:None (CatalogVariant keeps position as an attribute, not in
fields{}). Compare against the attribute, like images already do.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Email-canonical get-or-create, peppered-hash one-time codes with 10-min TTL, single-use,
5-attempt cap, and 60s resend cooldown; uniform new-or-known (no enumeration, §6.6). All
identity rules in the domain layer once (INV-6); scenario + invariant tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Four-layer package (main > domains > platform) per SD-0001 §6.2; GraphQL api layer
deferred. main.py is a stub so the top layer exists from the start (fleshed out in
the /healthz task). lint-imports green on the skeleton.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>