docs(m3): settle deterministic title and Call 2 design

Encode the recovered per-leaf title/short-description rule and the Call 2
input set into the point of record.

- REQUIREMENTS.md: METADATA-55 now produces the description only; METADATA-60
  carries the ruled input set; METADATA-80 is the deterministic title; new
  METADATA-81 is the deterministic spec-line short description; METADATA-85
  selects the patterns; REVIEW-15 declares the primary before Call 2;
  PUBLISH-55 carries an explicit name+SKU slug.
- CONTENT-WOO.md: per-leaf title and short-description catalog, slot order,
  dimension placement, and the Cook Woods provenance.
- PROMPTS.md: Call 2 inputs and output; the deterministic patterns are cited,
  not restated.
- CREATE.md, WOO-API.md, MILESTONES.md, task_breakdown.md updated to match.

Modeled on Cook Woods product-title form; the seven per-leaf prose templates
and Specialty cuts are parked in the M3 breakdown.
This commit is contained in:
2026-09-19 11:36:03 -07:00
parent 1dfff0b7c9
commit 120e0be871
7 changed files with 119 additions and 63 deletions
+69 -28
View File
@@ -10,67 +10,108 @@ Owns how listing copy is produced and the intent of the create payload. The wire
| Requirement | Impact on this design |
|---|---|
| REVIEW-10, REVIEW-15, REVIEW-40, REVIEW-50 | required prose, primary category, editability, limits |
| METADATA-40, METADATA-55, METADATA-60, METADATA-65, METADATA-66 | model scope, Call 2, context, dimension safety, logging |
| METADATA-70, METADATA-75, METADATA-80, METADATA-85, METADATA-90, METADATA-95, METADATA-110 | template fallback, non-blocking, prompt selection, fact block, overlay exclusion, control |
| METADATA-55, METADATA-60, METADATA-65, METADATA-66 | Call 2, inputs, dimension safety, logging |
| METADATA-70, METADATA-75, METADATA-80, METADATA-81, METADATA-85, METADATA-90, METADATA-95, METADATA-110 | deterministic copy, fallback, pattern selection, fact block, overlay exclusion, control |
| PUBLISH-5, PUBLISH-10, PUBLISH-15, PUBLISH-20, PUBLISH-25, PUBLISH-30, PUBLISH-31, PUBLISH-40, PUBLISH-45, PUBLISH-50, PUBLISH-55, PUBLISH-60 | payload and create outcomes |
| SETTINGS-30, SETTINGS-65 | brand voice and geo context; create status |
| METADATA-10, METADATA-15, METADATA-30 | categories, attributes, tags on the payload |
## 1. Copy sources
Titles and descriptions come from one of three sources (`REVIEW-10`):
Three fields, three sources (`REVIEW-10`):
1. **Typed** by the owner.
2. **Model** when Call 2 runs; the owner triggers it (`METADATA-55`).
3. **Template** as the fallback when Call 2 does not run (`METADATA-70`).
1. **name** — assembled deterministically by the server from the primary wood category's title
pattern and the dimension fact block (`METADATA-80`). The model does not write it.
2. **short_description** — assembled deterministically as a spec line from the primary wood
category's short-description pattern (`METADATA-81`). The model does not write it.
3. **description** — written by Call 2 when it runs (`METADATA-55`), from the inputs in
`METADATA-60`; with inference off the server produces it (`METADATA-70`).
The template guides style; when the model runs it writes the prose (`METADATA-80`). The model
writes prose only and never touches a dimension; every number comes from the dimension fact block
(`METADATA-60`, `METADATA-65`, `METADATA-90`). The dimension-overlay image is never sent
(`METADATA-95`). The owner can edit any result (`REVIEW-40`). All text respects the field limits
in `docs/contracts/WOO-API.md` §9 (`REVIEW-50`).
The primary wood category selects the title pattern, the short-description pattern, and the Call 2
prompt (`METADATA-85`, `REVIEW-15`). The owner can edit any field until create (`REVIEW-40`), and
every field respects the limits in `docs/contracts/WOO-API.md` §9 (`REVIEW-50`).
The Generate text control appears only when content generation is enabled and the endpoint is
The model writes the long description only, from the fact block; it never invents a dimension
(`METADATA-65`, `METADATA-90`). The dimension-overlay image is never sent (`METADATA-95`). The
Generate text control appears only when content generation is enabled and the endpoint is
reachable (`METADATA-110`); a failed generation never blocks create (`METADATA-75`). Every
generation is logged (`METADATA-66`).
## 2. Default templates
## 2. Deterministic title and short description
Placeholders use `{field}`; all math fields come from the deterministic pipeline, never the model
(`METADATA-90`).
Both patterns are assembled by the server and use only synced taxonomy terms and capture facts
(`METADATA-80`, `METADATA-81`). Placeholders use `{field}`; every number comes from the
deterministic pipeline, never the model (`METADATA-90`).
**Title** (hyphen separator; `{character}` is the primary figure term name, `METADATA-80`):
The shape follows the convention a working mill store uses: descriptor-led, dimension-light titles,
with the measurements carried separately. See "Provenance" below.
### 2.1 Title
Slot order:
```
{species} {length_ft}ft {length_in_remainder}in x {width_avg_in}in Wood Slab - {character}
[Figure] {species} [Live Edge] {noun} [(dims)]
```
1. `Figure` leads as a Title-Case adjective and is omitted when the Figure term is `plain`.
2. Grade is not used in the title.
3. `Live Edge` appears only when the Edge Type term is Live Edge.
4. There is no separator between slots.
5. Dimensions ride in the title only for the turning leaves, as a trailing `(L x W x T)`.
Per-leaf patterns:
| Leaf | Pattern | Example |
|---|---|---|
| Live edge wood | `[Figure] {species} Live Edge Slab` | `Figured Black Walnut Live Edge Slab` |
| Dimensional wood | `[Figure] {species} [Live Edge] Dimensional` | `Figured Red Oak Dimensional` |
| Knife blanks | `[Figure] {species} Knife Blank (L x W x T)` | `Figured Mirindiba Knife Blank (12 x 6.5 x 1.5 in)` |
| Bowl blanks | `[Figure] {species} [Live Edge] Bowl Blank (L x W x T)` | `Spalted Cherry Bowl Blank (8 x 8 x 3 in)` |
| logs and caps | `[Figure] {species} Log Cap` | `Figured Black Walnut Log Cap` |
| Pen blanks | `[Figure] {species} Pen Blank (L x W x T)` | `Figured Purpleheart Pen Blank (5.5 x 1.1 x 1.1 in)` |
| Pepper mill blanks | `[Figure] {species} Pepper Mill Blank (L x W x T)` | `Birdseye Olive Pepper Mill Blank (10 x 3.2 x 3 in)` |
`Specialty cuts` has no M3 pattern.
`length_ft = floor(length_in / 12)`, `length_in_remainder = length_in mod 12` (1 dp).
**Short description:**
### 2.2 Short description
One spec line, so the measurements appear even when the title omits them:
```
{species} Slab - {character}
[Figure] {species} {noun}, {length} x {width} x {thickness}, {bdft} bdft
```
**Description** (multi-paragraph):
| Leaf | Example |
|---|---|
| Live edge wood | `Figured Black Walnut Live Edge Slab, 9ft 6in x 24.3in x 1.75in, 18.4 bdft` |
| Dimensional wood | `Figured Red Oak Dimensional, 8ft 0in x 5.8in x 1.25in, 4.8 bdft` |
| Pepper mill blanks | `Birdseye Olive Pepper Mill Blank, 10in x 3.2in x 3in, 0.7 bdft` |
```
A one-of-a-one {character} {species} slab, {length_ft}ft {length_in_remainder}in long with an
average width of {width_avg_in}in and {thickness_in}in thickness ({bdft} bdft).
### 2.3 Description
Each slab is naturally shaped; width varies along the length at {width_min_in}in to
{width_max_in}in. Sold by the slab; dimensions as measured. {geo_sentence}
```
The long description is the model's prose when Call 2 runs (`METADATA-55`); with inference off the
server produces it (`METADATA-70`). The per-leaf prose templates that guide Call 2 are authored
with that slice and are not defined here.
`geo_sentence` comes from Settings and is omitted when unset (`SETTINGS-30`). The primary wood
category selects a specialized Call 2 prompt (`METADATA-85`).
### 2.4 Provenance
The title and short-description form was modeled on the live product titles of Cook Woods
(cookwoods.com), captured 2026-09-19. Borrowed: descriptor-led titles; dimension-free titles for
slabs, lumber, and caps; parenthetical dimensions only for turning stock; no separator; title case.
Not borrowed: their size-class nouns (`Mini Slab`, `Table`, `Micro Lumber`, `Long`) and pack counts
(`5 Pack`), which have no synced taxonomy term, and their grade adjectives, which are not used in
our titles.
## 3. Payload intent
The exact wire shape is `docs/contracts/WOO-API.md`. Intent:
- Only non-null fields are sent (`PUBLISH-55`).
- The payload carries an explicit `slug`: the sanitized product name plus the lowercased SKU.
Dimensions never appear in the slug (`PUBLISH-55`).
- `status` comes from `woo_create_status` (default draft); `SLAB-UAT-*` always draft
(`SETTINGS-65`, `PUBLISH-10`).
- Categories are the species leaf plus each wood-category leaf; attributes are the five locked
+19 -16
View File
@@ -9,8 +9,8 @@ Owns prompt storage, prompt inputs, and the two inference calls.
|---|---|
| METADATA-5, METADATA-10, METADATA-15, METADATA-30 | taxonomy choices and cardinality |
| METADATA-35, METADATA-40, METADATA-45, METADATA-50 | Call 1 inputs, constraints, pre-fill, precedence |
| METADATA-55, METADATA-60, METADATA-65, METADATA-70 | Call 2 trigger, context, constraints, fallback |
| METADATA-75, METADATA-80, METADATA-85, METADATA-90, METADATA-95 | non-blocking, fallback title, prompt selection, fact block, overlay exclusion |
| METADATA-55, METADATA-60, METADATA-65, METADATA-70 | Call 2 output, inputs, dimension safety, fallback |
| METADATA-75, METADATA-80, METADATA-81, METADATA-85, METADATA-90, METADATA-95 | non-blocking, deterministic copy, pattern selection, fact block, overlay exclusion |
| METADATA-100, METADATA-105, METADATA-110, METADATA-115 | feat mapping, prompt storage, button, failure |
| METADATA-66 | generation logging |
| SETTINGS-30 | brand voice and geo context |
@@ -59,31 +59,34 @@ recoverable or unrecoverable for the owner.
only when content generation is enabled and the endpoint is reachable.
**Inputs.**
- A fresh, full Call 1 context: prompt, Call 1 photos, and the Call 1 result. No provider thread
id is used.
- The confirmed or changed metadata from review.
- The clean processed photos.
- The metadata confirmed or changed in review, including the primary and secondary wood categories
and the parent-category path.
- The literal dimension fact block, exact strings for species, figure term, length, thickness,
average width, width min–max, and board feet; no length-by-width-by-thickness rectangle
assumption.
- Brand voice and geo context.
No provider thread id is used, and Call 1's raw prompt and result are not sent (`METADATA-60`).
**Constraints.**
- The model writes prose only and never invents or alters a dimension; every number comes from the
fact block.
- The dimension-overlay image is never sent.
fact block (`METADATA-65`).
- The dimension-overlay image is never sent (`METADATA-95`).
**Output.** `title`, `short_description`, `description`. The owner can edit the result.
**Output.** The long `description` prose. The server assembles `name` and `short_description`
(`METADATA-55`, `METADATA-80`, `METADATA-81`). The primary wood category selects the specialized
prompt (`METADATA-85`). The owner can edit the result (`REVIEW-40`).
## 4. Fallback and templates
- With inference off, deterministic templates produce name, short_description, and description so
create never lacks prose.
- The template is the fallback only; when Call 2 runs, the model writes and the template guides
style.
- The fallback title uses the primary figure term name as the character, with the hyphen
separator.
- The primary wood category selects a specialized Call 2 prompt.
- All generated text stays within the field limits in `docs/contracts/WOO-API.md` §9.
- With inference off, the server assembles the name and short description and produces the
description so create never lacks prose (`METADATA-70`).
- The deterministic title and short-description patterns live in `docs/contracts/CONTENT-WOO.md`
(`METADATA-80`, `METADATA-81`).
- The primary wood category selects the specialized Call 2 prompt (`METADATA-85`).
- All generated text stays within the field limits in `docs/contracts/WOO-API.md` §9
(`REVIEW-50`).
## 5. Prompt management
+2
View File
@@ -49,6 +49,7 @@ shape and the external constraints.
| — | `type` | string | `simple` (default) |
| create status | `status` | string | `draft`, `pending`, `private`, `publish`; default `publish` |
| sku | `sku` | string | unique; no documented format |
| slug (name + SKU) | `slug` | string | sanitized; WordPress dedupes on collision |
| price | `regular_price` | string | monetary string, 2 decimals |
| description | `description` | string | none documented |
| short_description | `short_description` | string | none documented |
@@ -126,6 +127,7 @@ Hard limits are verified from WordPress/WooCommerce source; the display caps are
| `short_description` | `wp_posts.post_excerpt` (`text`) | 65,535 | 160 | search snippet / meta description width |
| `description` | `wp_posts.post_content` (`longtext`) | ~16.7M | none | no word-count target; write for the page |
| `sku` | `wc_product_meta_lookup.sku` (`varchar(100)`, index `sku(50)`) | 100 | 50 | index prefix length |
| `slug` | `wp_posts.post_name` (`varchar(200)`) | 200 | 200 | WordPress `wp_unique_post_slug` truncates the base near 200 |
Sources: WordPress `schema.php`, WooCommerce `class-wc-install.php`,
`class-wc-product-data-store-cpt.php`, and Google Search Central (title links, snippets, SEO