Skip to main content

// catalog specialist

Run the lifecycle of every SKU.

Sync, classify, decide, execute — every product moves through one lifecycle state, gated by ALLOWED_TRANSITIONS, with a reversible decision row attached. Margin-aware. Tier-gated. Append-only.

Shopify Admin GraphQL 8 lifecycle states Dry-run + Live phases
decision_log · catalog
product     : "Brushed Linen Throw — Sand"
variant     : 'SKU-LIN-228-SND-L'
from_state  : ACTIVE
to_state    : ON_DISCOUNT
action      : DISCOUNT_TEST
delta       : −15% (€89 → €76)
window      : 14d, auto-revert

reason      : OPTIMIZE_CYCLE_FAILED (2 cycles)
              margin tier = A (verified)
              p75 winner floor = 2.4x ROAS
              current ROAS    = 1.6x (28d)

evidence    : [perf#9123, cycle#771, judge=0.88]
applied_at  : 2026-05-25T08:02:14Z
applied_by  : catalog_agent.discount_executor

status      : APPLIED (live)
reversal    : PRICE_RESTORE on day 14
next: classify cycle 09:00append-only

// what it does

Four phases. One loop. Every cycle.

The Catalog Specialist runs end-to-end every day — never a one-time sync. Each phase writes its evidence into the audit plane before the next phase is allowed to start.
01

Sync

catalog_sync pulls Shopify products, variants, and cost_per_item into the products table with Tier A cost confidence. performance_sync ingests Shopify orders + Google Ads spend into performance_daily per (date, variant_id).

catalog_syncperformance_syncTier A
02

Classify

self_calibrator derives store-specific thresholds — winner ROAS floor = max(2.0, p75 of your distribution). classifier assigns WINNER / MID / LOSER / INSUFFICIENT_DATA every cycle, never the same number twice.

self_calibratorclassifierp75 ROAS
03

Decide

decision_engine emits an Action enum per SKU — KEEP, SCALE_WINNER, OPTIMIZE_LOSER, DISCOUNT_TEST, DRAFT, VAULT, REVIVE_SEASONAL, FLAG_ORPHAN. Every action validated against ALLOWED_TRANSITIONS before write.

decision_engineALLOWED_TRANSITIONSAction enum
04

Execute

action_executor mutates Shopify (draft / publish / edit). discount_executor changes prices. copy_rewriter rewrites titles + descriptions via LLM, gated by trademark filter and uniqueness check.

action_executordiscount_executorcopy_rewriter

// lifecycle state machine

Eight states. One state per SKU. Always.

Every product variant lives in exactly one lifecycle state. Transitions are validated against the ALLOWED_TRANSITIONS map before any catalog write — invalid moves become operator-review rows, not Shopify mutations.
01

AUDIT

Fresh import, awaiting first decision.

02

PUBLISHED

Live on storefront, gathering signal.

03

ACTIVE

Selling within range — keep cycle.

04

OPTIMIZING

Copy or pricing under iteration.

05

ON_DISCOUNT

Discount window open, time-bounded.

06

DRAFTED

Unpublished, removed from catalog.

07

SEASONAL_VAULT

Held for next relevant window.

08

ARCHIVED

Permanently removed, recoverable on request.

ALLOWED_TRANSITIONS
AUDIT          → PUBLISHED, DRAFTED, FLAG
PUBLISHED      → ACTIVE, DRAFTED, OPTIMIZING
ACTIVE         → OPTIMIZING, ON_DISCOUNT,
                 DRAFTED, ARCHIVED
OPTIMIZING     → ACTIVE, ON_DISCOUNT, DRAFTED
ON_DISCOUNT    → ACTIVE, DRAFTED, ARCHIVED
DRAFTED        → PUBLISHED, SEASONAL_VAULT,
                 ARCHIVED
SEASONAL_VAULT → PUBLISHED (window only),
                 ARCHIVED
ARCHIVED       → DRAFTED (operator-only)

validate(from, to) → bool
invalid → review row, not mutation

// action enum

The full move set.

decision_engine emits one of these per SKU per cycle. Each action carries its own trigger, its own valid from-states, and its own pre-stored reversal op.
ActionWhat it doesValid fromTrigger
KEEPContinue selling at current price.PUBLISHED, ACTIVEWithin ROAS band
SCALE_WINNERFlagged for budget lift on paid side.ACTIVEROAS > p75 winner floor
OPTIMIZE_LOSERCopy + image regenerate cycle.ACTIVE, ON_DISCOUNTROAS < floor, 14d window
DISCOUNT_TESTTime-bounded price test, margin gated.OPTIMIZINGOPTIMIZE_CYCLE_FAILED
DRAFTUnpublish from storefront.ON_DISCOUNT, ACTIVESALES_ZERO_N_DAYS
VAULTPark as seasonal candidate.DRAFTEDSeasonal pattern detected
REVIVE_SEASONALRepublish ahead of season window.SEASONAL_VAULTCalendar trigger + signal
FLAG_ORPHANMissing cost data — operator review.AUDITTier C cost confidence

// cost confidence

Tier-gated writes. No guesswork.

Magistry will not move money or change prices on a SKU whose margin it cannot prove. Every variant gets one of three cost confidence tiers — and the tier decides what the agent is allowed to do.

Tier A

// data source

Shopify cost_per_item field, confirmed per variant.

// what is allowed

All actions enabled — price changes, scale, archive, publish.

Tier B

// data source

Inferred from supplier match or category-typical margin.

// what is allowed

Soft actions only — KEEP, OPTIMIZE, FLAG_ORPHAN. No discount writes.

Tier C

// data source

Missing or unverifiable cost — orphan SKU.

// what is allowed

Read-only. Operator review required before any catalog write.

Why this matters. Most catalog tools assume your cost data is right. Magistry assumes it isn't — every SKU is scored, every write is gated, and a Tier-C product never gets a discount on its own. Your margin policy is enforced in the type system.

// what operators say

Built to be trusted, not just to act.

“We pruned 1,200 dead SKUs in the first week — every move a row we could see and reverse. The thing that finally got buy-in from finance was the tier gate. Magistry simply refused to discount the orphan products. That was the conversation that ended the spreadsheet era for us.”

Maya Chen
Head of Ecommerce
Linen House

// catalog specialist

See your catalog the way Magistry sees it.

Connect a read-only Shopify token and the Catalog Specialist will draft its first audit cycle inside an hour — every SKU classified, every action explained, zero mutations until you flip the switch.

Dry-run by default · Append-only logs · One-click rollback