docs(m3): bring CONTENT-WOO onto branch; lock character and categories

Copy listing-copy/Woo payload spec from main. Lock {character} to the
primary Figure term name (Cathedral example). Lock categories[] to all
ready-set species and wood-category ids.
This commit is contained in:
2026-09-16 21:11:07 +00:00
parent 40080aee3a
commit d754cac9ef
3 changed files with 221 additions and 9 deletions
+19 -9
View File
@@ -15,7 +15,7 @@ This file is the Milestone 3 source of truth on branch `m3-ds`.
- **What is in M3** comes from Ty conversations on this branch (not from older milestone splits on `main`).
- **How Woo sync, metadata, pricing, and inference behave** is taken from the technical requirements on `main` (`CONTENT-WOO`, `DATA-MODEL`, `UX`, `ARCHITECTURE`, `OPENAPI`, `AGENTS`, `UAT-PRACTICE`, `DEPLOYMENT`) and written here so coding does not need to open `main`.
Related shipped specs: `docs/CAPTURE.md`, `docs/PHOTOS.md`. Product overview: `docs/PRODUCT.md`. Folder map: `docs/README.md`.
Related shipped specs: `docs/CAPTURE.md`, `docs/PHOTOS.md`. Listing copy and Woo payload detail: `docs/CONTENT-WOO.md` (from `main`). Product overview: `docs/PRODUCT.md`. Folder map: `docs/README.md`.
## Preconditions (already shipped)
@@ -217,7 +217,7 @@ FastAPI proxies all inference calls. The browser never holds the key.
### Templates (always available)
Defaults from `main` CONTENT-WOO:
Full defaults and Woo payload text live in `docs/CONTENT-WOO.md`. Summary here:
**title**
@@ -225,6 +225,8 @@ Defaults from `main` CONTENT-WOO:
{species} {length_ft}ft {length_in_remainder}in × {width_avg_in}in Wood Slab - {character}
```
Example from CONTENT-WOO: `Black Walnut 16ft 0in × 18.2in Wood Slab - Cathedral`
**short_title**
```
@@ -241,6 +243,12 @@ Each slab is naturally shaped. Width varies along the length at {width_min_in}in
{width_max_in}in. Sold by the slab; dimensions as measured. {geo_sentence}
```
**What `{character}` means (locked from CONTENT-WOO example + PROMPTS on `main`).**
The word after the dash in the example is `Cathedral`, which is a **Figure** attribute term.
Fill `{character}` with the primary (first) Figure term **name** from the ready set.
If somehow no figure is present, leave that slot empty (ready set normally requires ≥1 figure).
Do not confuse this with `feat-*` tags. Call 1 free-text "character / inclusions / voids / checks" map to `feat-*` tags, not to this title slot.
All template math fields come from the deterministic pipeline, never from the LLM.
---
@@ -279,7 +287,7 @@ Mill-owner path after Photos-ready:
"regular_price": "{price}",
"description": "{description}",
"short_description": "{short_title}",
"categories": [ { "id": <species and wood-category ids> } ],
"categories": [ { "id": <species leaf id> }, { "id": <wood-category leaf id> }, ... ],
"tags": [ { "id": <fig-* and feat-* ids> } ],
"images": [ { "src": "<media source_url>", "alt": "{species} {character} slab" } ],
"attributes": [ /* Edge, Figure, Grade, Thickness, Moisture term ids when present */ ],
@@ -404,17 +412,19 @@ Full request and response field lists on historical `main` `docs/OPENAPI.md` are
## Open decisions (must lock before task breakdown)
These came from comparing `CREATE.md` to the technical requirements on `main`. Do not invent Woo API shapes to fill them.
Locked from Ty conversation or from `docs/CONTENT-WOO.md`:
1. **`categories` on `POST /products`.** Ready set requires species plus wood-category leaf ids. The `main` CONTENT-WOO example only shows a species id in `categories[]`. Confirm: send **all** ready-set category ids (species + every wood category) as `[{"id": n}, ...]` per Woo REST product `categories`.
1. **`categories` on `POST /products`.** **Locked from CONTENT-WOO field rules:** send every ready-set category id (species leaf + each wood-category leaf) as `[{"id": n}, ...]`. The single-id example in CONTENT-WOO §2.4 is incomplete relative to those field rules.
2. **`attributes` element shape on `POST /products`.** `main` leaves `"attributes": [ … if present … ]` without fields. Need the exact Woo REST object fields for the five locked attributes (typically attribute `id`, `options` as term names, `visible`, `variation`). Prefer a live product sample from Whidbey Wood Store or the official Woo REST product-attribute docs Ty points us at. Do not guess.
2. **Template `{character}`.** **Locked from CONTENT-WOO example (`… Wood Slab - Cathedral`):** use the primary Figure term **name**. `feat-*` tags are separate (Call 1 free-text character/inclusions/voids/checks map there).
3. **Dimension-overlay PNG.** **Locked (Ty 2026-09-16):** include in Woo upload. Order is (1) clean calibration PNG, (2) dimension-overlay copy of that calibration PNG, (3+) other inventory PNGs in the order they were added in the web app. Cap remains ≤5.
3. **Dimension-overlay PNG.** **Locked (Ty 2026-09-16):** Woo image order is (1) clean calibration PNG, (2) dimension-overlay copy, (3+) other inventory PNGs in add order. Cap ≤5.
4. **Template `{character}`.** Default title/short/description templates need a `{character}` string. Confirm the source when `feat-*` is empty, one tag, or many (for example first feat tag name, figure term, or a dedicated field).
Still open (CONTENT-WOO does not fully settle these):
5. **Server persistence.** `main` OpenAPI assumes a full server slab row and status machine. This branch still centers the device draft. Confirm M3 server persistence: full slab store as on `main`, or a thinner path (Settings + taxonomy + pricing + create from an uploaded ready package) with device draft as the client source of truth until create.
4. **`attributes` element shape on `POST /products`.** CONTENT-WOO still has `"attributes": [ … if present … ]` with no fields. Need a live Whidbey product JSON sample, or Ty pointing at the official Woo REST fields to use. Do not invent.
5. **Server persistence.** CONTENT-WOO describes create sequence and payload. It does not choose full OpenAPI slab CRUD vs a thinner FastAPI path on this branch. Still need a lock before coding the server store.
Non-blocking notes (shipped M1/M2 win on this branch): fill target 90% and 800px floor (not main's 80%/1600); Vite + Svelte SPA (not SvelteKit docs); overlay draw spacing may differ from measure spacing by design.