← back to Maya Width Fix

README.md

76 lines

# maya-width-fix — TK-11029

Fixes the `maya_catalog.width` meta-tag pollution: at ticket open, **all 224**
`DWMR-8%` rows held the scraped garbage string `=device-width, initial-scale=1">`
(a `<meta name="viewport">` leak), so the Maya importer emitted 0 width metafields.

## Current state (read-only, verified 2026-09-02)

| metric | value |
|---|---|
| total `DWMR-8%` rows | 224 |
| originally polluted | 224 / 224 |
| **still polluted (residual)** | **2** — `DWMR-80026`, `DWMR-80211` |
| clean width | 222 |
| `width_inches` NULL | 17 (genuine multi-width, ambiguous by design) + 2 residual |

The 2 residual rows (`cozy-bed-fellow` / `cozy-nestle`) return **HTTP 404** on
mayaromanoff.com (discontinued) → width is **unrecoverable from the web**; needs a
Maya rep/PDF. A rep width-request email is drafted (unsent, Steve-gated). **Do not guess.**

## Authoritative source

`mayaromanoff.com/collections/<slug>` → the spec-table `Width` cell. `$0` plain-fetch
GET, no browser/proxy/creds. Each collection resolves to exactly one width string,
classified as SINGLE (one roll width → `width_inches` derivable) or MULTI_WIDTH (one
pattern genuinely offered in 2 roll widths, **no per-SKU width exists** → keep the full
string, `width_inches` = NULL).

## Files

| file | role | writes? |
|---|---|---|
| `widthlib.py` | pure width classifier/parser (SINGLE / MULTI_WIDTH / META_POLLUTION / …) | none |
| `test_widthlib.py` | unit tests, fixtures = live DB distinct values + negatives | none |
| `diagnose.py` | read-only DB diagnosis → `evidence/diagnosis.json` | none |
| `authoritative_source.py` | read-only re-scrape + DB reconciliation source-proof | none |
| `pipeline.py` | **deterministic DRY-RUN** correction plan + rollback artifact | **none** |
| `restore.py` | one-command UNDO from a restore-map (finalizer/undo tool) | DB (undo only) |
| `evidence/` | committed stable copies of the JSON proofs | — |

`scrape.py` / `backfill.py` / `backfill-multiwidth.py` + `restore-map-2026-*.json`
are the **prior** (already-applied) one-time backfill + its rollback maps — left intact.

## Run

```bash
python3 test_widthlib.py            # unit tests (exit 0 = pass)
python3 diagnose.py                 # current counts + residual rows
python3 authoritative_source.py     # re-scrape + prove DB == live source
python3 pipeline.py                 # DRY-RUN plan, currently-polluted scope (2 rows)
python3 pipeline.py --simulate-all  # DRY-RUN plan over all 224 (proves convergence)
python3 pipeline.py --apply         # REFUSED — dry-run only (see below)
```

## Finalizer (/root) apply path — GATED

`pipeline.py` never writes. Applying a `maya_catalog` correction is a **canonical
Mac2-staging-DB write** and stays gated. To apply a reviewed dry-run plan:

1. Re-run `python3 pipeline.py --simulate-all` (or polluted scope) to regenerate the
   plan + a fresh `restore-map-dryrun-<ts>.json` (rollback artifact) against live DB.
2. Review `plan[].sql` — each is a single bounded `UPDATE … WHERE dw_sku='…'`.
3. Apply the `sql` lines (finalizer authority) inside one transaction.
4. **Undo** at any time: `python3 restore.py restore-map-dryrun-<ts>.json`.

Current recommendation for the finalizer: **no apply needed.** 222/224 are already
correct; the 2 residual are unrecoverable (rep-gated); the only `--simulate-all` diff
is 3 `wisping-weaves-montauk` rows where the **stored DB value is cleaner**
(`137.2 cm`) than the live page's current vendor typo (`137.2 m`, curly quote) —
cosmetic, `width_inches` NULL either way → keep the DB value.

## Constraints honored

Read-only diagnosis + dry-run only. No canonical DB / Shopify writes, no
deploy/restart/spend/send/DNS/delete/remote-push. Unrelated edits preserved.