← back to Dw Yolo Loop
docs/boost-hue-sort-runbook.md
167 lines
# Boost Hue-Sort Runbook — "Solid → Sparse" per color collection
**Goal:** every color collection lists products **most-solid-target-hue first**,
ramping down to single-dot / no-hue last. Two mechanisms are in play; this runbook
is the durable, server-side one (Half 2). Dev theme: **NewWall Template [Dev]
#143739584563**, store `designer-laboratory-sandbox.myshopify.com` (= live
www.designerwallcoverings.com).
---
## How it works (data layer — already shipped)
Every active product carries hue-coverage metafields computed once from its
featured image (PIL HSV histogram, $0, no Gemini):
- **`custom.hue_coverage`** — JSON, all 14 hues, e.g. `{"blue":80.5,"red":2.1,...}`.
74,604 products. Read by the **client-side** sorter (see Half A below).
- **`custom.cov_<hue>`** — flat `number_decimal`, one per hue, e.g. `cov_blue = 80.5`.
99,847 written across the 7 giant-collection hues. Read by **Boost server-side
sort** (Half B below). Boost can only sort by a scalar metafield, not a JSON key —
that's why the flat `cov_<hue>` fields exist.
Sort intent everywhere: **higher coverage = earlier**.
---
## Half A — client-side reorder (small/mid collections, ALREADY LIVE on dev theme)
24 collections ≤12k products. Each has an asset `hc-<handle>.js`
(`window.HC={hue, map:{handle:coverage}}`) + the generic sorter
`newwall-huesort.js`, gated in `layout/theme.liquid` by a color-handle allow-list.
The sorter sets each Boost card's CSS `order = 100000 − coverage×100` and re-applies
on every infinite-scroll append (MutationObserver). Verified 0-inversion on
`blue-wallcoverings`.
Limitation: it can only reorder the cards **currently loaded in the DOM**, so it's
ideal for collections a shopper can scroll through, but NOT a true global sort for
the 12k–33k giants → those use Half B instead.
To re-push Half A assets after editing:
```bash
cd /tmp/newwall-theme
ONLY=(--only layout/theme.liquid --only assets/newwall-huesort.js)
for f in assets/hc-*.js; do ONLY+=(--only "$f"); done
shopify theme push --theme 143739584563 \
--store designer-laboratory-sandbox.myshopify.com --nodelete "${ONLY[@]}"
```
---
## Half B — Boost server-side sort (the 10 GIANT collections) — DO THIS IN THE DASHBOARD
Reaches the **entire** collection (works the same on page 1 and page 130). No client
payload. Requires Boost dashboard login (Boost AI Search & Filter, bc-solutions.net).
### Per collection, once:
1. Boost dashboard → **Filter & Sort → Sorting**.
2. **Add custom sort** → name it e.g. `Solid → Sparse`.
3. Rule: **Sort by metafield** → pick the collection's `custom.cov_<hue>` →
**High to Low**.
4. Boost → **Merchandising / Collections** → select the collection →
set **Default sort = `Solid → Sparse`**.
### Collection → metafield mapping (ALL 34 color collections)
`custom.cov_<hue>` is now written for every color collection's members (127,880
metafields total across 14 hues), so **every** collection below can use Boost
server-side sort — not just the giants. Set each one's default sort to its hue's
metafield, High → Low.
| Collection handle | Metafield |
|---|---|
| `beige-wallcoverings` | `custom.cov_beige` |
| `white-wallcovering-collection` | `custom.cov_white` |
| `white-wallcoverings` | `custom.cov_white` |
| `white-wallpaper-collection` | `custom.cov_white` |
| `grey-wallcovering` | `custom.cov_gray` |
| `gray-wallcoverings` | `custom.cov_gray` |
| `silver-wallcoverings` | `custom.cov_gray` |
| `brown-wallpaper-collection` | `custom.cov_brown` |
| `brown-wallcoverings` | `custom.cov_brown` |
| `green-wallpaper-collection` | `custom.cov_green` |
| `green-wallcoverings` | `custom.cov_green` |
| `green-wall-textures` | `custom.cov_green` |
| `yellow-wallpaper-collection` | `custom.cov_yellow` |
| `yellow-wallcovering-collection` | `custom.cov_yellow` |
| `yellow-wallcoverings` | `custom.cov_yellow` |
| `blue-wallpaper-collection` | `custom.cov_blue` |
| `blue-wallpaper` | `custom.cov_blue` |
| `blue-wallcoverings` | `custom.cov_blue` |
| `navy-wallcoverings` | `custom.cov_blue` |
| `metallic-wallpaper-collections` | `custom.cov_gold` |
| `metallic-wallpaper-collection` | `custom.cov_gold` |
| `gold-wallcoverings` | `custom.cov_gold` |
| `black-wallcoverings` | `custom.cov_black` |
| `teal-wallcoverings` | `custom.cov_teal` |
| `pink-wallcovering-2` | `custom.cov_pink` |
| `pink-wallcovering-collection` | `custom.cov_pink` |
| `pink-wallcoverings` | `custom.cov_pink` |
| `red-wallpaper-collection` | `custom.cov_red` |
| `red-wallcoverings` | `custom.cov_red` |
| `red-wallcovering-collection` | `custom.cov_red` |
| `orange-wallcovering-collection` | `custom.cov_orange` |
| `orange-wallcoverings` | `custom.cov_orange` |
| `purple-wallcovering-collection` | `custom.cov_purple` |
| `purple-wallcoverings` | `custom.cov_purple` |
Per-hue metafield counts: beige 23,599 · white 21,796 · gray 14,647 · yellow 10,899 ·
green 10,889 · blue 9,946 · gold 8,572 · brown 8,151 · black 4,813 · pink 4,094 ·
teal 3,646 · red 3,613 · orange 1,967 · purple 1,248.
Products without the metafield (image had ~0% of that hue) sort to the tail — correct.
---
## Verify it worked
Open the collection on the live domain under the dev theme:
```
https://www.designerwallcoverings.com/collections/<handle>?preview_theme_id=143739584563
```
First cards should be the most-saturated/solid in that hue; scrolling deep should
keep descending (Boost paginates already-sorted, so no client re-sort needed here).
Spot-check a metafield via Admin GraphQL:
```bash
TOKEN=$(grep -m1 '^SHOPIFY_ADMIN_TOKEN=' ~/Projects/secrets-manager/.env | cut -d= -f2-)
curl -s -X POST https://designer-laboratory-sandbox.myshopify.com/admin/api/2024-10/graphql.json \
-H "X-Shopify-Access-Token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"query":"{product(id:\"gid://shopify/Product/7506089607219\"){title metafield(namespace:\"custom\",key:\"cov_blue\"){value type}}}"}'
# -> cov_blue = 100.0 (number_decimal)
```
---
## Retire the client-side interim (prerequisite now DONE)
All 14 scalar `cov_<hue>` metafields are written for every color collection
(127,880 total) — so the data prerequisite is satisfied. To switch fully to one
consistent server-side mechanism:
1. In Boost, set every collection in the table above to its `custom.cov_<hue>`
default sort (High → Low).
2. Once all are set and verified, drop the client block from `layout/theme.liquid`
(the `color_handles` assign + the `hc-<handle>.js` + `newwall-huesort.js` script
tags) and re-push — Boost then owns the sort everywhere, page 1 through the tail.
Do step 2 ONLY after step 1 is confirmed live, or collections briefly lose the sort.
Generators (reusable, idempotent, $0):
- `/tmp/cov_scalar_fanout.py` — writes `custom.cov_<hue>` from `/tmp/hue_computed.jsonl`
via Admin GraphQL cursor enumeration (NOT storefront products.json — that HTTP-400s
past ~page 100 and can't reach a 33k collection's tail).
- `/tmp/hue_fanout.py` — recomputes histograms if `/tmp/hue_computed.jsonl` is ever lost.
---
## Standing constraints (don't violate)
- **Dev theme #143739584563 only.** Never publish, never touch the live theme.
- Metafields are **additive** — never touched product status/title/tags/images or the
$4.25 sample variant.
- PIL only for image analysis (never Gemini — key compromised).
- Source data: `SHOPIFY_ADMIN_TOKEN` in `~/Projects/secrets-manager/.env`, API 2024-10.