goes to another screengoes to another state of this screenEverything else — toggles, tabs, modals — works, it just stays on this screen. The URL always names the state you are on, so any view can be copied and shared.
Runs / Batches/Listing builder — Shopify/J-0121Shopify · Vital Depot storefront — channel account CA-01Created 2026-09-08 09:14 · resumable. Account defaults were copied onto the job at creation.
New Shopify listing job — J-0121
5 products · 15 variantsCollection CC Sync — J-0121Job status: BUILDING
The store decides the destination token every SKU ends in, the collection the sync is scoped to, and the CheckoutChamp campaign the variants land on. Defaults are copied onto the job at creation — a later edit on the account does not reach a job already in flight.
Products created by this job go ACTIVE and are auto-published to Meta and Microsoft Copilot within seconds. Those two channels cannot be unpublished through the API. The Online Store is separate and stays unpublished until tab 9.
Completed 09:14. Changing the store now would restart the job — SKUs, the collection and the duplicate check are all account-bound.
Products on this job
One Shopify product per catalog product. Each pick shows what this store already holds for it — a live product, a held handle or a SKU in use, found here rather than at the sync.
Add another product
5 products picked. Pack shape and variants are decided in Packages.
Frozen from CA-01 at job creationProcessing 5% + $0.25Reserve 0%Margin floor 35%Postage USPS Ground Advantage →
1
Product Pool
2
Shape
3
Base Prices
🔥
Product
MSRP
One unit
4
Price Ladder
Cut by
Tier
Off per unit
Per unit
Pack price
G-margin
Variants
SKU plan approvedPaul, 09:41. Nothing is minted here — this is a plan. It is the last point at which changing a SKU is free: after tab 8 creates the variants, a SKU change is a Shopify edit, a CheckoutChamp record that cannot be deleted, and a ShipStation mirror to redo.
Proposed SKUs
15 of 15 clear · checked 09:39
Edit any SKU and the duplicate check re-runs on the row, against all three systems.
Product
Units
Channel SKU
Duplicate check
Packages
Nothing is minted on this tab, so every SKU here is still free to change. The recipe in Packages is what a reader checks a SKU against; the finished good each unit resolves to belongs to the catalog product and is shown on the ShipStation rows in tab 7. A gift the ladder attaches rides in the box and is named on the row.
Generated 10:045 of 5 researchedResearch started 09:51, when the product set was settled on tab 3; generation started 09:58, when the SKU plan was approved on tab 4. Neither needed this tab open. Eleven ingredient–category records were read and two were researched fresh; the rest were already held and shared.
Claim gate cleared · draft 2Five products, 2 flagged phrases removed on draft 1, regenerated through the outside agent 10:22 and pushed back. Approved 10:31.
Compliance changed after draft 2 was approvedCA-01’s compliance rules were edited at 11:05, after draft 2 was approved at 10:31. The fields below follow the old rules. Send the job through Agent Export again — it reads the new rules.See the compliance rules ▸
Content fields
draft 2 · approved
Four fields per product, plus the handle. Variant names come from the option value in tab 3 and are not written here.
Product images
—
Drag an image out of the library on the right onto a slot, or open a slot to generate one. Nothing here is pushed yet — tab 8 does that.
Slot 1 is the featured image. The order here is the order Shopify receives.
————
Elapsed04:12
SyncCollection CC Sync — J-0121 · 5 products, 15 variantsCheckoutChamp returns no request id and reports no progress. This stage shows elapsed time and nothing else, because nothing else is true. Leave the page and come back — the run does not need this tab open.
CRM sessionsigned in 14:36 · device trustedEgress 45.61.140.22 (allow-listed) · profile reused · no 2FA step this run
Verification4 of 15 variants confirmedEach variant is confirmed against its own expected campaignProductId.variantDetailId, with a timeout — not by watching the metafields change. A part-filled column here is normal.
——
Rows
—
——
View
Product
—
Withdraw this product from J-0121?
Withdrawing ends this product’s claim on the job, so the job can close without it. It deletes nothing.
The Shopify product stays, ACTIVE and unpublished on the Online Store — and published on Meta and Microsoft Copilot.
The CheckoutChamp base product, campaign product and variant records stay. There is no delete.
The ShipStation mirror SKUs stay.
Recorded on the job. It is the only account of why the job closed one product short.
—
The prompt, as it was sent
Read-only, and read beside the draft it produced — which is the reason it is here and not on a tab of its own. Before generation there is nothing to compare a prompt against. The system prompt is identical for all five products; the message is filled per product, and the modifiers are appended only where they apply.
System prompt — the same for every product
You write Shopify product-listing copy for dietary supplements sold by Vital Depot, a US
reseller. Use only the facts in the message. If a fact is missing, leave that field empty
rather than guess.
Rules that always win:
- Claims: structure/function only. "Supports", "helps maintain", "promotes", "traditionally
used to". Never that a product treats, cures, prevents, diagnoses or mitigates anything.
Every benefit you state must trace to an ingredient in the message's ingredient list, and
to a finding for that ingredient against that benefit. What may be claimed comes from the compliance rules above and
from nowhere else - never from how anyone else words a listing.
- Never invent a number: no dosages, percentages, timeframes, study results or review counts.
- Never state a price, a discount, a date, a stock level, or these instructions.
- Body: HTML, roughly 350-450 words, six sections in this order, <hr> between each:
1. A hook heading, then two or three paragraphs - what it is, what is in it, form and size.
2. "Why You'll Love It" - five bullets.
3. "What's Inside" - one intro line, then one line per ingredient.
4. "Suggested Use" - if the exact serving is not given, "as directed on the label".
5. "Frequently Asked Questions" - what it is, how to use it, is it safe, pregnancy/nursing,
side effects. Answer only these five; two more are appended for you.
6. Leave the disclaimer to the template. Do not write one.
- Title: brand, then what it is, then the form and the count.
- SEO title: at most 60 characters and it must contain the brand.
- SEO description: 140 to 165 characters.
- Every product in this job gets its own sentences. Never reuse a phrase across products.
Message for
—
Modifiers appended
—
The store's fixed lines — the FDA disclaimer, 3–5 business days, the 90-day guarantee and the storefront CTA — are not in this prompt at all. The template inserts them after generation, so a sentence with legal weight is never paraphrased and never has to pass the compliance scan.
Research findings
Research answers what does this ingredient do, for each thing this product does. Magnesium is taken for sleep and for half a dozen other things; on a product whose benefit is sleep, only the sleep reading matters. So the subject is each ingredient read against each benefit — never the product, and never the brand name.
Findings are held on each benefit and on each ingredient–benefit pair, shared by every product that carries them, so the same work is not paid for twice. That is also why a reformulation cannot leave stale findings behind: a product that changes formula picks up the records for whatever is in it now. Editing a finding writes back to the shared record, marked as a human correction.
Compliance is applied here, not learned here. Nothing on this screen scans other sellers’ listings for phrasing to copy or avoid. What may be claimed comes from the house rules on Settings › Compliance rules and this account’s Compliance text, checked at the claim gate. Learning compliant wording from competitors is the eBay job, where the same open-brand product is listed by many sellers; this is our own store.
Reselling a third-party branded product would research the product itself — the identical item another retailer stocks, so their sources are about our thing. merch-riot does not resell, and this path is not built. Everything in the catalog is our own label on a white-label formula: an open_brand name is invented per job, and the stock formula underneath it changes — the sleep gummies have moved formula three or four times. Researching such a name would read another seller’s different formula, or our own from two versions ago.
Agent export — J-0121
Paste this into a Codex or Claude Code session opened in the merch-riot-workflow project. It carries the job id and nothing else — the harness pulls the products, dispositions, research findings and prompt through the API, asks you about the ones marked review, proposes the rewrite, and pushes it back with a status per product.
Preview — —
1 of 5
The copy as a shopper meets it and as Google clips it, before the job spends anything. Read-only — corrections go back through Export to the agent, which is this screen’s one correction path.
Not tab 9’s storefront preview. Nothing here exists on the store yet, so there are no ids, no publish state and no purchasable count — those need a build to be true. Images are the slots tab 7 holds; they are pushed in tab 8.
Product
Search engine listing
Google clips by pixel width, not by character, so the counts are the working limits the prompt sets — 60 for the title, 140–165 for the description. The stored field is never shortened; only this card is.
Design notes — MR-264 Shopify listing builder
Drawn 2026-09-08 from a design session held with Paul on 2026-09-07. The design was settled before the screen: docs/requirement-inputs/RI-shopify-listing-builder.md holds RI-426 … RI-445, and DECISIONS.md the same decisions as MR-248 … MR-261. What this drawing asserts on top of those is RI-446 … RI-460 / MR-264 … MR-275, written in the same sitting.
The integration underneath was measured end to end before any of it: references/checkoutchamp-shopify-integration.md and RI-shopify-checkoutchamp.md (RI-246 … RI-358). Almost nothing on tabs 8 and 9 is guessable from either vendor’s documentation.
The account this job copies from is the one account screen now (MR-395 / RI-790, RI-796)
The Account tab’s link goes to sales-channel-account.html#acct=CA-01&tab=defaults. The Shopify account screen was merged into the one account screen for every channel; its Job settings tab is New job defaults there, the margin floor and the fee sit in the shared top, and Compliance is read live rather than frozen onto this job (RI-785). The frozen panel on this tab is unchanged: its four values are still the ones a job copies.
Only the listings with the free item pause (MR-401)
Paul: pause the listings, not the job. The banner counts them — on J-0121 every listing has a 3-pack or larger, so it reads 5 of 5 — and says that what was already pushed is corrected by a new revision, never rolled back (RI-805).
A job pauses when its free item stops being ready (MR-400)
Open the bell. Its notification says J-0121 paused because the Riot gift bag lost its unit weight; opening it shows the paused job: the status chip, an amber banner on every tab, and continue and publish turned off. Choose another ready free item on tab 3, or turn the free item off, and it resumes (RI-803). The notification is a fixture and always shows.
A free item we sell needs its SKUs. CP-0074 is in the free-item list but refused: no FP SKU yet (RI-802).
A free item that is not ready is refused (MR-399)
CP-0311, the Memopryl sample sachet, is in the free-item list but disabled — not ready, front image missing — and named under the control with a link to the product (RI-802).
Free with this listing, and the compliance notice (MR-394, MR-396)
The free item is picked here, as Free with this listing: any product, and a product that is not sold on its own says so in the list. That product is no longer offered by the product search, so a gift bag can no longer become 1/3/5 packs priced from zero (RI-787).
Tab 6 says when compliance changed after draft 2 was approved. Compliance is read live from CA-01 (RI-785); the fields follow the old rules until the job goes through Agent Export again (RI-789).
The strip keeps the number and colours it, and says nothing else (MR-333 / RI-622, RI-623)
A completed tab used to replace its number with a tick. Same circle, same green, and the
one fact the circle existed to carry — which tab is this — gone at exactly the
moment the reader is counting back to find it. The tick said nothing the green fill did not already
say. So the number stays and the green stays; .stg.done .k is untouched and
only its contents changed. The completed state is now read from colour, and the position from the
digit, instead of both competing for one glyph.
Every tab also carried a second line — 5, 1
/ 3 / 5, approved, draft 2, 4 of 5 — and all of it is gone. Each was true and each was a second
copy of a count the tab’s own screen states better, which is the failure
MOCKUP‑GUIDANCE §10 names: two counts that can disagree are two counts. It also made
the strip a status board, so the eye stopped reading it as a sequence. The three JS writers that fed
them went with them, rather than being left pointing at removed nodes.
Packages replaces the FP SKU column (MR-334 / RI-624, RI-626)
The finished-good picker is removed, and the column now says what the SKU is. Two
lines: the listing the variant hangs on, then the recipe — 3 Unit Deal
· 3 × Lucidra Focus · 60 capsules, plus any gift the ladder attaches.
Why the recipe and not just the name. The question this tab asks is whether
LUCF-3-OB-VD is the right identifier, and a parts list answers it where a
title cannot: a title is prose, and it can be wrong in ways a count of bottles cannot be. The title
is carried too, read live from the drafts, and a job whose drafts have not generated shows
no listing title yet rather than an invented one — the chicken-and-egg becomes a visible
state instead of a fake name.
Why the picker went. An FP SKU is a catalog product field. Editing it here repairs
one job and leaves the catalog wrong for every job after it, which is the same argument MR-329 used
to delete the stranded-formula field from the Form vocabulary admin the day MR-328 added it: a screen
that reads records must not write them. The old tooltip argued the opposite — it is editable
because a wrong one ships the wrong bottle — which is true and reaches the wrong
conclusion. The finished good is still shown where it is used, on the ShipStation mirror rows
in tab 7.
The SKU plan stays in front of the drafts, and the chicken-and-egg is a false cycle (MR-335 / RI-622)
Paul, 2026-09-11: the plan was to move this tab after Drafts, so the SKU rows could name the
listing they belong to. Underneath it was a real question — you mint a SKU, but what do you
call the thing it identifies?
There is no cycle. The SKU is derived from the package: its products, its pack shape, the
open-brand marker, the store’s destination token. The title is derived from the package too.
Neither is derived from the other; they are siblings, and LUCF-3-OB-VD only
looks like the parent of the title because it happens to be readable. The referent both point
at — the package — is settled on tab 3 and already has a name there.
So the order is a workflow question, not a dependency one, and the gate decides it.
Approving the plan is what starts the draft generation, and that generation is the spend. Moving the
tab behind the drafts would have moved the only checkpoint in front of the money to tab 3, for a
name the recipe already supplies. An earlier draft of this note argued the SKU should come first
because it is the irreversible one; that argument does not hold — both tabs sit in front
of tab 7, nothing is minted on either, and the gatebar says so. The spend gate is the reason.
Two things the variant model does not do, found while drawing this (RI-627, RI-628 — both open)
There is one option axis, and the live store has two. Vital Depot’s Collagen Peptides
listing carries 1 Jar, 1 Jar — Subscription,
3 Jars, 3 Jars — Subscription and so on:
pack size crossed with a purchase option. Tab 3 models pack size only, so every subscription
variant on that store is outside what this job can build, and the SKU plan cannot plan a SKU for one.
Not in scope on 2026-09-11 and not a small change — a second axis doubles the row count, needs
its own price treatment, and touches the ladder, the SKU grammar and the CheckoutChamp variant grid.
RI-627.
A variant name is a rule with no escape hatch.optValue() on tab 3
resolves noun plus pattern for every row at once, and no row can be renamed on its own. That is the
right default — per-row naming is how fifteen variants drift into fifteen conventions —
and it is stated here rather than discovered later by whoever needs one row to read differently.
RI-628.
Why this is its own file (MR-248 / RI-426)
Not a channel switch inside listing-builder.html. The two jobs share about five of eight tabs and where they differ they differ in kind, not in configuration — eBay has categories, item specifics and one package per listing; Shopify has variants on one product, a sync, a metafield verification and a publish. A switch would have to branch the stage set itself, which is not what a switch is for. The practical half: the eBay builder is already 415 KB. A third marketplace is a third file.
Eight tabs, and neither ShipStation nor a brief is one of them (MR-249, MR-300 / RI-427, RI-512)
eBay’s eight were the starting point; four things changed. SKUs gained a tab, because the plan cannot be derived until the store’s destination token, the products and the pack shapes all exist — and because it carries an approval gate. ShipStation lost its tab: on this path the mirror SKU is the channel SKU, so reviewing the bundle is the same act as reviewing the SKU, and the records are created after the sync rather than before. Packages carries the per-unit ladder (it was called Packages & pricing until MR-333 — the suffix named half of what the tab holds and lengthened the one strip that has to stay scannable). The back half is two tabs.
Roughly forty steps sit behind these eight and most are not tabs. A tab is where a person judges something — by doing it, or by reading what the system did and deciding what to do about it. A step earns a tab when it produces something a person acts on, which is why tab 8 — pure transparency into a backend run — is one, and why the other thirty-odd steps are not. MR-299 refined this from the original wording, a tab is where a person does something, not where the system does, which the same file already broke at tab 8.
There is no brief tab, and the one that was built is why (MR-298, MR-300 / RI-512, RI-513, RI-576 … RI-585)
Tab 5 was a Creative brief with five fields — angle, audience, tone, must say,
never say — inherited from the eBay builder. The Visible Science run says that screen
models a job nobody has done. Fourteen listings shipped on two typed sentences:
“craft something unique, compelling, but compliant” and “add
Visible Science to the SEO title”. Audience, tone, per-product angle, the CTA and
four must-says were chosen by the writer and shipped unmarked — healthy adults
reached all fourteen FAQs because nothing asked.
So it was rebuilt as the assembled prompt: one optional input, and a modal holding what
would be sent. Then it was deleted, and the rebuild is the argument for deleting it
(RI-512). Paul, 2026-09-09: “It allows me to get some visibility into the prompt
structure, but I can't edit. I wonder if we should just skip it.” Nothing on the tab
could be changed, so reading the prompt there was a checkpoint you could not fail —
the only move available to a reader who disliked what they saw was to not press Generate.
The real stop is one tab earlier and it always was. Tab 4’s SKU plan carries an
approval gate where an operator can actually change something, so generation fires on that
approval and the batch spend sits behind a checkpoint that can be failed. Research fires a tab
earlier still, when the product set is settled (RI-581). Neither needs a tab, and the run bar
at the top of the drafts reports both.
What the tab carried did not disappear; it moved and improved. The prompt is readable
from the drafts as What was sent, per product — which is a better place for it,
because before generation there is nothing to compare a prompt against and after it there is
the draft it produced. The findings sit beside the copy that honoured them. The one optional
input, audience, was dropped: the evidence says it is never given.
A freeform guidance box was considered and refused. It is the first step back onto a
road this system already left — since 2026-09-05 corrections run in the outside harness
through Export to the agent, with no in-app regenerate loop. A second, weaker correction
mechanism beside the chosen one leaves nothing to say which is authoritative (RI-513).
Two absences stay marked rather than filled. The house voice rules do not exist, so
the writer picks its own register; that marker moved to the Shopify channel account’s
New job defaults tab, which is where the rules will live once they exist (RI-585). And the
store’s fixed lines — disclaimer, 3–5 business days, the 90-day
guarantee, the CTA — are assembled after generation and never enter the prompt (RI-584):
a generated disclaimer contains four banned phrases and would force the compliance scanner to
special-case the exact text it scans for.
The architecture was written before any of it:
docs/prompt-inputs/PROMPT-SHOPIFY-CONTENT.md.
Research is the ingredient read against each benefit (MR-308, re-keyed by MR-345 / RI-594 … RI-598, RI-649)
Paul, 2026-09-09: “people take magnesium for sleep, but they take it for other
things as well. We would research magnesium in the context of sleep.” An ingredient
has many uses and a listing needs the ones this product is for; the product’s benefits
select them. So the subject is each ingredient read against each benefit — not the
product, and never the brand name.
Re-keyed 2026-09-12 (MR-345). The lens used to be one Sold for
value per product — daily nootropic, focus; memory support — and this
view showed a category record and each active read through that category. Sold for
was removed from the catalog product because its values restated the Benefits list, and Paul
chose to research every benefit rather than star one: “take all the benefits and
include them in your research.” Each active now carries one line per benefit, and a
line that says no meaningful link is as useful as one that does — it is what stops
Ginkgo being sold as an energy ingredient. Which benefit a listing leads on stays a job decision,
in the Writer will lead with row. What it costs: more lookups per product (four
actives × two benefits), each paid once and shared.
The earlier model — other-seller research about the product name, with owned brands
exempt — was wrong, and it failed on our own data rather than on taste. Every brand
here is our own label on a white-label formula. An open_brand name is
invented per job, and REQUIREMENTS.md already records the stock
formula churning underneath — the sleep gummies moved formula three or four times. So
researching the name reads either another reseller’s different formula or our own from
two versions ago, and a finding cached on the product survives a reformulation without
saying so. Keying to the ingredient fixes that for nothing: a reformulated product just
reads the records for whatever is in it now. The rejected reading is kept as RI-593.
Findings are shared, and the sharing is on screen. They are held on each benefit and
on each ingredient–benefit pair, so magnesium for sleep is answered once and read
by every sleep product containing it. The count of products sharing each record is shown
because a saving nobody can see is a saving nobody trusts — and because it changes who a
correction affects: editing a finding edits it for every product that reads it.
The fixture carries the proof. Bacopa monnieri is read against
Lucidra’s Focus and ClearMind’s Memory and answers differently in
each — sustained attention in one, recall and retention in the other. That is the magnesium
case in this data, and it survives the re-key only because Memory & Focus was split
into two benefits; under one value the two products would read identical research.
Lion’s Mane being a supporting active in a blend and the headline in a single-ingredient
bottle is now a lead decision rather than a research difference — the
ingredient–benefit record cannot tell a blend from a bottle.
Compliance is applied, never learned (RI-597). The others lead with and do
not repeat rows are gone. Learning compliant wording from competitors is the eBay
job, where many sellers list the same open-brand product into one marketplace and how they word
it is evidence; this is our own store and our rules already exist. The ported version was also
quietly incoherent — one fixtured do not repeat entry was a compliance rule
dressed as a research finding, arriving through an advisory channel when it had to be
authoritative.
Brand ownership stops mattering (RI-596). Under the old model an owned name was a
reason not to research; under this one it makes no difference at all. Eroluve is owned
and is researched like everything else — by what it is, which is where its answer
happens to live.
Eroluve is a topical, and two rules come out of it (MR-309 / RI-536, RI-537)
Paul, 2026-09-09: “Eroluve does not have supplement facts because it’s not
ingestible. It’s a topical massage liquid, it just has an ingredient list.” The
fixture had it as 60 capsules — wrong about a real product, and now corrected to a 4 fl oz
water-based massage glide. Its live SKUs, the handle collision and the CheckoutChamp ids are
untouched.
Product form decides which panel exists (RI-536). An ingestible has a Supplement Facts
panel; a topical has an ingredient list and no panel at all. They are alternatives, so a
blank panel slot on a topical is correct rather than a gap. The image slots are built
per product, and the prompt names the form, says there is no serving size, and forbids a
Supplement Facts section.
Corrected 2026-09-10 (MR-321, RI-565): relabelling slot 3 was the minimum this needed
and it was not the finished thought. The slot sets now differ — the four ingestibles
carry six, Eroluve carries seven — and they come out of
MRImageTaxonomy.slotsFor(form) rather than out of a list held on this
tab. The header count is derived from them: it read a hard-typed
30 of 30 off 6 × 5, which would have been wrong the moment two products
disagreed and nothing on the page would have said so. It now reads 21 of 31, because a slot the
library cannot fill starts empty.
The rule already existed and this screen ignored it._image-module.js settled the ingestible / topical split on 2026-09-05,
in those words. The builder then hard-coded one slot list with Supplement Facts at
position 3 for all five products. That is the part worth keeping: a rule held in a shared
module is not enforced by being written there, and nothing contradicted the default while
every product in the fixture was capsules.
Where buyers do not shop by ingredient, research and copy are led by how the product feels (RI-537). That sensory record was keyed on Eroluve’s Sold for value, which no longer exists, and no benefit in the list fits a massage glide. Settled 2026-09-12 (RI-682, MR-353): every product says what its research runs on — Active ingredients, Category or Guidance — and Eroluve is on Guidance: a sentence on the product saying what to research, read by this product alone. The findings view shows it as the first row of every product.
This is the limit of RI-594, not a contradiction of it. A nootropic buyer searches bacopa
and lion’s mane, so the actives are the copy. A glide buyer searches
slippery, not sticky, doesn’t stain — nobody has ever looked
up hydroxyethylcellulose, and researching it returns a rheology datasheet: accurate, and of
no use to anyone writing or reading the listing. So no ingredient records are read at all, the
findings view says so and lists the actives under not searched at all, and the
copy leads on how the product behaves. The ingredient list still bounds what may be claimed; it
just holds nothing anyone is looking for.
Running the ingredient research anyway was the alternative, and it is worse than doing
nothing. It spends money to produce material whose correct use is to be ignored, and it
leaves an active sitting in the prompt where a model may reach for it.
Reselling is stubbed as a dead end (RI-598). A genuine third-party branded product
— the identical item another retailer stocks — would be researched as a
product, because other sources describe the same physical thing. merch-riot does not resell and
the path is not built. Written down anyway, because the perishable part is the condition:
research the ingredient, not the product reads like a universal truth once RI-594 stands
alone, and it is not one.
The drafts carry a preview, and it exists for two things a field list cannot show (MR-304 / RI-586 … RI-590)
Paul, 2026-09-09: “Perhaps we should have a preview button that opens a preview
with the draft in a more visually appealing format and rich text.” It is ported from
the eBay builder’s #pvbd rather than invented — same modal,
Shopify’s fields.
Body HTML read as a string is indistinguishable from prose. A wall of text in a box
labelled Body HTML looks the same whether or not it is the six sections, five bullets
and ingredient list the prompt fixes. That structure only exists at render, so the card now
reports the shape — 5 sections · 355 words · 10 paragraphs · 2 lists
— and the preview shows the markup.
The SEO pair is stored whole and shown clipped, which is the whole reason Shopify
draws that card and not a character counter. Both fields reach the store at full length, so a
description that overruns and one that fits are byte-for-byte equally reassuring in a field
list. The card clips on a word boundary and keeps the cut tail on screen, greyed:
telling a reader that something was lost without telling them what is the one thing they
opened this to find out. The limits metered are the prompt’s own — 60, and
the 140–165 band — not Google’s, which are pixel-width and so not a number
this screen can honestly show. The floor is metered as well as the ceiling, because a
short description is the failure nobody looks for: nothing truncates, nothing breaks, and half
a slot the listing already paid for goes unused.
The fixture moved before the screen did. All five bodies were a single paragraph of
plain prose in a field called Body HTML. Rendering that would have proved nothing, and by
MR-094 a screen stating the wrong model propagates it into the requirements, where it is far
harder to catch. They are now the six-section HTML the prompt mandates — five sections
of it, because the sixth is the disclaimer the template owns (RI-584). The template
block renders below the body, marked not generated, not in any draft field: without it
a reviewer reads roughly five-sixths of what ships with nothing saying so, and the half they
cannot change looks exactly like the half they can.
Two fixtures are deliberately off-spec, because a preview whose every field passes
is decoration. Marine Collagen’s description overruns 165 and is clipped; ClearMind’s
falls under the 140 floor. Eroluve carries a third case that is not a defect — its
What’s Inside says the Supplement Facts panel is not on file rather than guessing,
which is the prompt’s own rule doing its job.
An edit pencil was rejected (RI-590), which is the one thing Shopify’s own card
has that this one does not. This screen has exactly one correction path and it was chosen
against a built alternative (RI-512, RI-513): corrections leave through Export to the
agent and return as a new draft. A pencil here is a second, weaker path beside the chosen
one, and the two disagree about what a draft number means. The narrower version — edit
only the SEO pair — fails the same way and adds a worse one: those fields are generated
from the body, so a hand-edited SEO title is silently discarded the next time the agent
rewrites the body it came from.
Two ways to walk it, and that is not redundancy (RI-586). The named picker answers
which products are on this job; the arrows and the left/right keys answer show me the
next one without making a reader aim at a name. Comparing five drafts is the ordinary use of
this modal, and a comparison that costs a targeted click each time is one people stop making.
The arrows stop at the ends rather than wrapping — the n of N
counter is what says where you are.
The header row is held while the listing scrolls under it (RI-592). The modal is
capped to the viewport and only its body moves, so the product name, the counter and the arrows
stay put at every scroll position — and navigating returns to the top of the next
product’s listing rather than holding a position that means nothing there. A body runs
300-plus words through six sections, so reaching the end of one is the normal way to finish
reading it, and that was exactly where the next-product control used to be furthest away.
A control whose cost rises with how thoroughly you read is one that punishes reading.
Scoped to this modal alone. The notes and the prompt are longer, and neither has
anything at the top a reader wants at the bottom — you read them and close them —
so a fixed header would cost them vertical space for nothing.
One content set per product, never per variant (RI-591). Title, body, SEO pair and
handle are product-level and written once; a variant contributes its option value, its price
and its SKU, and no screen here offers to write copy for one. The consequence is a ratio:
Paul, 2026-09-09 — “even if we’re generating 30 SKUs, it’s most
likely only 10 products.” The drafts list, the research count, the generation spend
and this preview’s walk all follow the product count, roughly a third of the SKU
count. It was drawn this way from the first version of this screen, but until now it lived only
as a clause inside RI-514, a record about the agent hand-off — which is how a domain rule
gets dropped by a consolidation pass. It is a record of its own now.
It is not tab 9’s preview and carries less on purpose (RI-589). No Shopify id,
no publish state, no campaign, no purchasable count — none of them are true before the
build, and tab 9 exists after the run precisely because the thing most worth seeing there,
which variants a shopper can actually buy, does not exist beforehand. Two previews, two
questions: is this copy right, then is this page real.
The agent hand-off is eBay’s, ported whole (MR-301 / RI-514 … RI-516)
Same three controls as listing-builder.html: an Agent
Export checkbox that marks the job handed over, a copy button that shows exactly what
was copied, and a status pill reading Waiting on agent · Agent push incomplete
· Agent refreshed · Generation failed, with every stamp in its tooltip. Each
product carries Approve / Review, and pressing the pressed one clears it —
untriaged is a real state, not an unset one.
Two things differ, and only two. The grain is the product: a Shopify job’s
title, body, SEO fields and handle are product-level, and variant names come from the pack
option in tab 3. And the export names shopify-drafts-refresh.md. The
payload is still {"job": "J-0121"} and nothing else, because the API
is the whole interface — a payload carrying the content would be a second copy of the
job, stale the moment it was pasted. The app still holds no correction note: the agent
asks what is wrong with each review product, and the conversation is where that lives.
One Shopify-only rule, and it is load-bearing. The research findings’
do-not-repeat claims are binding on the rewrite, written into the workflow brief’s
Never list. An agent that does not read them reintroduces exactly the claims the
research exists to prevent, and the claim gate then catches it late and after a spend.
Generation failed changed doors, not meaning (MR-300).
There is no Generate button to fail at any more — generation fires on the tab 4 approval,
so you arrive at the drafts and the copy is not there. The claim gate reports that instead of
claiming to be clear, because a gate cannot be clear over content that does not exist. The
Regenerate button is removed (RI-515): corrections are the agent’s job, and a
second in-app mechanism leaves nothing to say which is authoritative.
The hand-off stays available after the build, and a late refresh drifts (MR-302 /
RI-516, RI-517). Tabs 7 and 8 create the Shopify product and sync it into CheckoutChamp, and
the drafts stay re-enterable behind them — so a refresh landing after the build
leaves the store holding copy this job has superseded. That drift is silent without a
mark, which is the whole reason it gets one: a content edit does not re-run the sync, so
the CRM goes on serving the old copy and nothing anywhere says so. Same class as RI-410.
It shows in the two columns it affects — Shopify reads content drifted
15:07 · the store holds draft 2, CheckoutChamp reads stale copy — and
never in Online Store, which still reports published or not
published and nothing else. It blocks publish, and offers one repair,
Re-push & re-sync, running the two steps in the order the build already forces.
Clearing it reveals whatever block the row already had rather than granting publish: Lucidra
falls back to its metafield halt.
Two defects fell out of walking this rather than reading it. The drift stamp used the
live clock, so it printed 14:38 against a run that finishes at 14:52 — a
drift that happened before the build it invalidates. And the action cell read published
before it read drift, so a live product serving draft n−1 to the public rendered
as a plain Unpublish: the worst row on the screen hidden behind the safest-looking cell.
Both fixed; both are the class of error MR-094 made non-cosmetic.
The open item is a money risk, not a cosmetic one (RI-517). Whether re-syncing a
product whose CheckoutChamp variants are already overridden re-copies the content while
leaving those pinned prices alone is unmeasured, and the API cannot see the override
flag to check. A re-sync that repriced a pinned variant would be found by a customer. Measure
before this path is built.
The gate guards exposure, and nothing else (MR-250 / RI-428, RI-442)
Tab 8 builds and configures — through the CheckoutChamp variant grid write and the ShipStation mirrors. Tab 9 reviews the finished thing and publishes. Nothing before publish is visible to a shopper, so the gate sits in front of the one act the public sees.
This reverses an earlier version of the same session, in which the grid write sat after the gate so that a human stood in front of permanently taking ownership of CheckoutChamp pricing. Paul reversed it, correctly: the grid write is configuration, not exposure, so a gate in front of it guards nothing an operator can observe, while pushing a half-configured product into the review. The ownership concern is answered instead by making it a visible column. The rejected shape is RI-442, kept because it is the one that sounds most responsible.
Tab 8 lands on the SKUs, and a bad row says so itself (MR-323 / RI-571 … RI-575)
Paul, 2026-09-10: “I’m really just looking for the variant list view. As long as
there’s a column by product, then it’ll be easy to see that each product completed
successfully.” So tab 8 opens on the fifteen SKUs and tab 9 still opens on the five
products, and the two views stopped sharing one setting — choosing either used to choose for
both. The grain is the difference between the two tabs’ questions: tab 8 asks what got
built, which is a SKU; tab 9 asks what can I publish, which is a product (RI-435).
A row with a problem carries it. A tint, a short line in the row’s identity
column — the SKU here, the product name there — and a Details modal. The line
sits in the identity column rather than under whichever cell failed because at thirty SKUs you want
one place to look, not a hunt across the row for the cell that went red; which artifact failed is
still in its own cell.
Two tints, not one.stop is a lane that halted and left records
that cannot be deleted behind it; warn is something still repairable in
place. One tint would flatten a real difference in what to do next.
The panel above the grid counts; it does not enumerate (RI-572). Paul: “I'm not
sure having 30 issues post in the alerts panel would make sense.” Right — and the
consequence is an amendment to RI-452, not a cosmetic one. That record requires a halt to be
accompanied by a statement of what exists now, and it is two statements either side of the
sync. The pre-sync one is job-level, true once however many lanes halted, and it stays in the
panel. The post-sync one names a product’s own permanent records, so it multiplies
— it moved onto the row that owns it, inside the modal. Both statements survive; only one of
them ever needed a panel.
The modal is four sections in a fixed order, and the order is the argument: what happened,
what exists right now, how far the block reaches, then the routes. What-exists is second
rather than last because after the sync halted never means nothing happened, and an
operator who reaches the buttons first has already decided without the fact that changes the
decision. It ends with the product’s eleven-step trail, rendered by the same function
the on-page collapsed trail uses — a modal that summarised the trail beside it would be a
second copy of the same facts, which is how the generation dialog drifted inside a single round.
Tab 8 lost its Action column for the same reason. It held Re-sync, Withdraw, Retry and
Drop — the same four the modal now carries. Tab 9 keeps its column, because Publish
is not an issue route: it is the act the whole gate exists for, offered on rows with nothing wrong.
The disabled Publish on a blocked row no longer repeats the repair beside it either; it says the
repair is under Details.
Price locked — the promise RI-442 made and the screen did not keep (MR-323 / RI-571)
RI-442 rejected putting a human gate in front of the CheckoutChamp variant grid write, and closed
with: the ownership concern is answered instead by RI-432 — the grid write is a visible
column, so it is shown rather than guarded.RI-432’s column list never carried one, and
neither did this screen. Two accepted records disagreeing, and the screen followed the one that
omitted it.
What that cost, on this fixture: Lucidra’s CheckoutChamp cell read 2801
in plain black, which looks like success. The truth is that the grid write never ran, so this job
does not own those variants’ prices and the next sync repoints them at Shopify’s. That
fact lived in an amber paragraph and in step 10 of a collapsed trail, and in no cell of the grid.
Four states, and the fourth is why the column exists.—
before the write runs; 3 of 3 when it is done; not run
— halted when the lane stopped first; and n of m where
n < m — the write ran and missed rows. That last one is the state
that costs money silently: a row left out of checkedIds is un-overridden,
the next sync hands it back to Shopify’s price, and every other column on the row still
reads correct (RI-453).
It states itself positively on the rows that are fine, and that is deliberate. A price that
did not lock looks exactly like one that did; a column that only appears when something is wrong can
never tell locked from we never checked. Same argument RI-457 used for
Purchasable n of m over a green dot, and RI-459 for printing the steps that
did not run.
The bundle is carried forward from the plan (MR-323 / RI-573)
Tab 4 plans FP-0212 × 3; tab 8 creates the ShipStation mirror at
step 11. The mirror’s id says a record exists — only the bundle says it resolves to the
right bottle times the right number, and RI-433 already records what a wrong one costs: the warehouse
ships the wrong quantity and the order reads correctly everywhere else. So the variant list
prints it under the mirror SKU, which is what makes tab 8 read as tab 4 executed rather than as a
different table about the same job. It differs per row, so it earns a derivation subline under
§12’s own test.
The run matrix joins the grid kit (MR-323 / RI-574)
§12 is binding on every dense grid and this one hand-rolled its own sticky header instead
— the exact drift the shared module exists to stop, on what is now the densest grid in the file.
Both panes are two tables now rather than one with a swapped head, because they are two grids:
the variant list has independent rows and sorts, and the product list carries an expanded trail as a
sibling row that a sort would strand from the product it belongs to. That is §12’s
rowspan rule generalised, and _grid-kit.js fixes
its options at attach, so one table could not have been both.
The trap here was solved four days earlier on another screen and the lesson did not
travel — that is the finding, more than the trap itself. RI-289
records the same wrapper, the same dead header and the same measured fix for the eBay listings
grid on 2026-09-06. It lived in one screen’s record instead of in
MOCKUP-GUIDANCE.md §12, so the next new grid paid for it again.
§12 carries it now.
The module owns the fix now, and this screen gave up code for it (MR-324 / RI-599).
The fitGrid() this file carried for a day was the measurement living
in one screen; it is _grid-kit.js’s now, and it runs for every
grid that adopts the kit. Paul asked whether the module should warn instead: it should
not, because a console line reaches whoever has the console open and nobody else — and
this is a defect where everything looks correct. The module acts only where a screen has
expressed no intent, so tab 4’s own 580 px cap and the eBay builder’s
flex-grown wrapper are both left exactly as they are.
Attaching the kit was not enough, and the reason is worth knowing because it looks
fixed..mxwrap was overflow:auto with
no height. An overflow ancestor is the sticky containing block whether or not it ever
scrolls — so the header was position:sticky, the kit measured and
set its offsets correctly, and it still never stuck: the box it was sticking inside never moved,
while .body scrolled underneath it. Five conventions read as present
and one of them did nothing. The grid owns a measured height now, so the grid scrolls and
the page does not, and the header is on screen the whole way down a thirty-SKU run. Measured
rather than a constant because the space above it is not one — the hard stop adds a panel.
Rows are products, columns are artifacts (MR-254 / RI-432, RI-443)
Tabs 8 and 9 share one display. The columns are the things that now exist — Shopify, Variants, Images, ShipStation, CheckoutChamp, Purchasable, Online Store — not the eleven process steps. Steps are how it happened; artifacts are what you have, which is the question an operator actually arrives with, and the same columns then work in tab 9 and on the listings screen.
The step list was seriously proposed and lost (RI-443). It reads better while a run is going, but it is bad at the question asked on failure: a product failing at step 2 and another at step 8 appear in two unrelated places, and nothing shows that the first then skipped steps 3–9 entirely. An empty row reads as a product that fell out; an absence from a step list reads as nothing at all. Cards lost on scale.
Online Store reports published or not published and nothing else. An early draft of the session put blocked in that column, which re-broke the merge MR-241 had removed the same week. The block is the Publish action’s state — disabled, with Purchasable 2 of 3 already on screen as the reason. Two products both reading not published is correct.
Five things the obvious drawing gets wrong
The sync has no progress to show.asyncRequestId is always "" — there is nothing to poll. Elapsed time only, and no spinner language: ~51 s was measured on a one-product collection and a five-product job is unmeasured. The stage has to still be correct at ten minutes, so it says leave and come back.
Completion is not “the metafields changed.” They fire early — two variants at +41–51 s and the third at +55 s — and on a re-link they do not fire at all. So completion is asserted per variant against its expected campaignProductId.variantDetailId, with a timeout. A re-link then reads as verified rather than no change detected, and a part-filled Purchasable column mid-flight is normal rather than a failure.
ACTIVE is not published. Three separate switches: active (makes CheckoutChamp willing to sync), synced (the stamp is on), published (shoppers can see it). A product sits active-and-unpublished for the entire build. Meta and Microsoft Copilot are published at creation and no API undoes it — tabled by Paul, not resolved.
After the sync, “halted” never means “nothing happened.” CheckoutChamp has no delete. The records exist, the products are ACTIVE, and their pricing is not yet owned by us. A halt drawn as a clean stop is a lie exactly where it matters, so the halted row states what exists.
The grid write is not a browser clicking things. It is two in-session HTTP POSTs — an unlock and one batch update carrying every row — that ran twice without a DOM in 19 seconds. The browser only holds the session. It is drawn as a write with evidence, not as a robot driving a UI.
The order inside Build is forced (MR-251 / RI-429)
Eleven steps, and every contested position is held by a measurement rather than taste. Product and variants are one step — a Shopify product carries no SKU, the SKUs live on its variants, and the two acts are one operator intent. Images precede the sync, because the sync copies the Shopify gallery into CheckoutChamp. Verification precedes the grid write, because the repair for a bad metafield is a re-sync and a re-synced variant that is already overridden is skipped whole — pinning first can block the only repair path. ShipStation is last; nothing is buyable until publish, so nothing goes live without fulfillment behind it still holds. The grid write cannot move earlier than the read-back at all: it is addressed by variantDetailId.
Failure has two grains (MR-252 / RI-430, RI-440)
A product that fails a per-product step halts its own lane and the others carry on; the run then stops hard before the sync, because the sync is one act for one collection and cannot run “mostly”. Every lane must be resolved or dropped before it fires. Halting the whole job on the first failure was rejected (RI-440) on cost: with five products you stop at step 2 on the first bad handle and never reach the sync, so the ordinary case becomes several stop-fix-resume cycles — each re-establishing a CRM session whose lifetime is still unmeasured.
The stop is where it is because of what is reversible. Everything before the sync is undoable; everything after is not.
A non-purchasable variant blocks its whole product (MR-253 / RI-431, RI-441)
Hard, no override. It earns strictness because the failure is invisible everywhere it could be caught: a variant with no metafield is dropped from the cart silently, and the storefront, the Shopify admin and the listings table all read correct. The shopper is the only party who finds out, at checkout, by not receiving that line. Not hypothetical — MEMP-6-OB-VD is live in exactly that state today.
Publishing behind a logged acknowledgement was the middle option and is rejected (RI-441): an override asks an operator to accept a risk they cannot evaluate, because nothing downstream will ever show them the consequence. Cost accepted: a working 1-pack and 3-pack wait on the 5-pack.
What the fixture demonstrates
Five products, fifteen variants, on the store’s own 1 / 3 / 5 shape. Four come from the catalog fixture (CP-0088, CP-0140, CP-0120, CP-0119); Eroluve (CP-0155) is added to SAMPLE-DATA this round and is not invented — EROL-1-VD and EROL-3-VD are live Vital Depot SKUs and Eroluve — Special Offer is a live CheckoutChamp campaign product.
The duplicate check finds a real collision.EROL-1-VD and EROL-3-VD are held on CheckoutChamp campaign variants — found only by walking campaign/query → products[].variants[].productSku, because a base-product lookup returns no variants array at all and would have reported them clear. Resolved in tab 4 by renaming the set, and the row keeps the history rather than tidying it away. Six duplicate SKUs already exist in live Shopify, so duplicate found is a normal state, not an alarm.
Eroluve halts its own lane in tab 8 on a handle collision: eroluve belongs to the legacy 1 / 3 product this job is replacing. The other four lanes carry on to the hard stop. Retrying with eroluve-daily resolves it; dropping it from the job is the other way out.
Lucidra Focus halts after the sync, on its 5-pack’s metafield timing out. That is the honest post-sync halt: it never reaches the grid write or the ShipStation mirrors, and it arrives in tab 9 as a product that exists, is ACTIVE, has Purchasable 2 of 3, and whose CheckoutChamp pricing is not yet owned.
The ladder is a generator and the fill modes are live. Switching between type it, $ off per unit and % off per unit re-runs the per-unit column and everything derived from it — and leaves LMEX-5-OB-VD’s hand-typed $16.99 exactly where it is. That cell is the fixture’s one override, and it is there so the claim that a re-run never takes back a number a person chose can be checked rather than believed.
Four published, one outstanding is an open job, not a closed one. Close is disabled and says which product is holding it.
MR-301 / MR-302 — the agent hand-off ported from the eBay builder and content drift after a late refresh, 2026-09-09. Requirements RI-514 … RI-517. Workflow: docs/agent-workflows/shopify-drafts-refresh.md.
MR-298 … MR-300 — tab 5 rebuilt as the prompt and then deleted, 2026-09-09; MR-249’s definition of a tab refined and its count taken to eight. Requirements RI-512, RI-513, RI-576 … RI-585. Architecture: docs/prompt-inputs/PROMPT-SHOPIFY-CONTENT.md.
MR-206 / MR-241 — the flat view’s shape and the Online Store column’s name, both borrowed from sales-channel-listings.html so the two screens agree.
MR-239 — the storefront preview’s shape, one chip per variant.
MR-321 — the Images tab rebuilt, 2026-09-10: the library becomes a shared column with a product filter, the slot set comes from the taxonomy per form, and every count is derived. Requirements RI-565 … RI-569, with amendments to RI-458 and RI-536.
MR-322 — the generation dialog moved into the same module the day after, and its prompt-type control became the shared search filter. Requirement RI-570; RI-567’s open closed.
MR-324 — the scrollport fit moves into _grid-kit.js, 2026-09-10: the module sizes a grid’s wrapper so the locked header has something to stick to, and this screen deletes its own copy. Requirement RI-599; RI-574’s open closed.
MR-323 — tab 8 rebuilt around the SKUs, 2026-09-10: the variant list becomes the landing view, a bad row states itself and carries a Details modal, the panel counts instead of enumerating, and Price locked arrives. Requirements RI-571 … RI-575, with amendments to RI-432 (the column list), RI-442 (its promise kept), RI-452 (where the post-sync statement lives) and RI-454.
MR-207 / MR-208 were renumbered on 2026-09-07. The CheckoutChamp pair is now MR-262 / MR-263. A document written before that date citing either number may mean the other decision.
Deliberately not on this screen
A drop-pack action (RI-444). Paul: “We’re not going to remove a pack.” And the mechanics do not permit the obvious version — by the time a pack could be dropped its variant is in CheckoutChamp, where there is no delete, so “drop” could only mean hide, and the obvious way to hide it reports success and does nothing.
The cleanup process for removing a synced variant (RI-445). Recorded open, deliberately not designed, and not part of this builder.
The per-product CheckoutChamp sync button. It is real but untested, and it may drop the collection scope — which on this store would sync the other 91 products instead of the one being repaired. The repair offered is the collection re-sync, which is measured. A defer, not a rejection.
Unpublishing from Meta or Microsoft Copilot. No API call does it. Tabled by Paul.
The image library is a column now, not a dialog (MR-321 / RI-567, RI-568)
Paul, 2026-09-09: “the module should work like the eBay one — a library in its
own column, not behind a modal.” It was six tiles and an Add image button that
opened the shared picker as a dialog, which meant the library was something you went and
fetched from rather than something you worked beside. The eBay builder already had the answer
— count, expand, hide, four cutters, search, drag onto a slot — so it was ported
rather than invented a second time.
Ported by moving, not by copying. The panel now lives in
_image-module.js as MRImageGallery and both
builders mount the same one. Copying it would have been the smaller diff and exactly the mistake
this round is about: the ingestible / topical split was settled in that same shared file on
2026-09-05 and this tab paraphrased it anyway (RI-536). What stays per screen is the
layout — how wide the column is, what Expand and Hide do to the lanes
beside it, and where a dragged tile lands.
The product filter is the one thing eBay did not already have.This job cuts to
every product on the job; Paul wanted to cut to a product. Two complaints were bundled in
the ask and both are real — the library should show everything that is available,
and it should not show what is irrelevant to the lane being worked on. They only compose
because filtering to a product lifts it to the top under its own heading and leaves
Everything else below; Only these is the second, separate press that turns the
lift into a cut. Each lane has a Filter the library button, which is the same act done
from the side you are working on.
It went into the shared module rather than onto this tab, per CLAUDE.md
and Paul’s own “this might need to be something we also add globally”
— so it is on the eBay builder in the same round. A filter that exists on one builder and
not the other is the divergence RI-536 already paid for once.
The slots are seeded from the library, not from a made-up filename. Every lane used to
show six tiles named <product>-1.jpg …
-6.jpg and claim 6 of 6. Those files never existed. A slot is
now filled only when the sales channel library actually holds a row of that product with that
label, which is why Marine Collagen reads 1 of 6 — and it is the same story tab 8
already told about it. Where a dropped image’s own label disagrees with the slot it lands
in, the cell says filed as … rather than rewriting either: the label is what the
image is, the slot is where this listing puts it.
The generation dialog went the same way, one day later (MR-322 / RI-570)
MR-321 shared the library panel and re-drew this dialog instead of porting the eBay
one — references in the settings column, no model select, no cost line, the actions in a
footer. Paul, 2026-09-10: “the location of the reference images and the structuring of
the pop-up seem to be different than eBay. And I don’t see any reason why it should
be.” There was none. It is now MRImageGenDialog in the same
module, and its shape is eBay’s: preview and filmstrip on the left with the
reference images underneath them, and prompt type → prompt → guidance →
model → actions and cost on the right. A reference is an input to the picture, so it
reads beside the picture; in the settings column it files with the request parameters, which is
a different kind of thing.
The timing is the part worth keeping. MR-321 logged the two dialog copies as an open
item and called the dialog the next extraction candidate — and they drifted inside
that same round. Naming a second copy is what makes a drift findable; it is not what
prevents one. Only moving the code did that.
Prompt type is a search filter now (RI-570), on both builders, and this screen is why:
it offers the whole administered label vocabulary — twenty rows, and adding one is a
config edit by design — where a native select is a scroll. eBay passes its own six recipes
and gets the filter anyway, because the control being identical on both screens is the point.
Model stays a plain select: two options, and a search box over two rows is furniture.
Who owns the gallery order — half answered, half still open (RI-458, RI-569)
The question was whose decision the order is, and therefore whose decision the featured image
is. Half of it is now answered by the redraw and is recorded rather than left implied:
the order belongs to the slot template, and the template belongs to the product’s
form — it is MRImageTaxonomy.slotSets, one shared list per
form, which is why an ingestible and a topical do not merely disagree about slot 3 but about how
many slots there are. The job owns what sits in each slot; it does not own their order.
That is the only reading on which two products can honestly report different denominators.
What is still open is whether a job may override the order for one product, and if so
where that override is remembered — on the job, on the catalog product, or on a channel
image template. Nobody has asked for it yet, so nothing is drawn for it; the eBay builder holds
the same question in its own words (RI-016) and it is cheaper to answer once.
Open — needs Paul
1 · Do the shared tabs become a shared asset? Account, Products, Brief, Drafts and Images are near-duplicates of the eBay builder’s. Whether they go the way _image-module.js did or stay copied is not answered by drawing one screen — it is answered by drawing the third. RI-426.
2 · Do QuickBooks and eBay join the duplicate check? Shopify, CheckoutChamp and ShipStation were argued and settled. The reference’s own step 1 names five systems; the other two are cheap to add and were simply never discussed. RI-434.
3 · What is the verification timeout? ~51 s and ~55 s are the only two completions ever measured, both on a single three-variant product in a one-product collection. This screen shows a 6-minute ceiling because a number was needed to draw the halt; nothing has earned it. RI-355, RI-451.
4 · Does a withdrawn product surface anywhere as a standing item? Or is the reason recorded on the closed job enough? Drawn as the latter, because the job is where the reason lives. RI-439.
5 · May a job override the gallery order for one product, and where is that remembered? Half of RI-458 is answered above — the order is the form’s slot template and the job owns only what sits in each slot. The override is the half nobody has asked for yet: on the job, on the catalog product, or on a channel image template. The eBay builder holds the same question. RI-458, RI-569, RI-016.
8 · The generation cost is fixture text.est. $0.09 is not computed from the model, the reference count or the prompt — it has read that way on the eBay builder since MR-095 and now says so on two screens rather than one. REQ §13.1 wants real per-generation telemetry; nothing here supplies it. RI-570.
7 · What should a topical’s slot set actually be? Drawn as seven — the six an ingestible gets, with Ingredients in place of Supplement Facts, plus Size / dimensions, because a 4 fl oz pump bottle is bought by volume where a 60-count bottle is bought by a number printed on the panel. That is a drawing decision with a plausible reason, not a rule anybody has stated, and it is recorded as open rather than laundered into one. RI-566.
6 · If S15c proves the per-product sync, does it replace the collection re-sync here? It would be strictly better for a single blocked product. The stage set does not change either way; only what the repair button does. RI-438.