# Create capability Status: SPEC · 2026-09-18 · Milestone M3. Behavior and acceptance for turning a Photos-ready slab into a submitted WooCommerce product. This doc cites requirement IDs; `docs/REQUIREMENTS.md` is the only normative text. Interface detail lives in `docs/contracts/` (`API.md`, `WOO-API.md`, `DATA-MODEL.md`, `PROMPTS.md`, `UX.md`, `CONTENT-WOO.md`). ## Requirements impact | Requirement | Impact on this capability | |---|---| | REVIEW-5, REVIEW-10, REVIEW-15, REVIEW-20 | ready set, prose fields, primary category, inline nudges | | REVIEW-25, REVIEW-30, REVIEW-35, REVIEW-40, REVIEW-45, REVIEW-50 | price, read-only math, stale picks, editability, SKU and caps | | METADATA-5, METADATA-10, METADATA-15, METADATA-20, METADATA-25, METADATA-30 | synced taxonomy, cardinality, no term creation | | METADATA-35, METADATA-40, METADATA-45, METADATA-50 | Call 1 inputs, results, confidence gate, precedence | | METADATA-55, METADATA-60, METADATA-65, METADATA-66 | Call 2, inputs, dimension safety, logging | | METADATA-70, METADATA-75, METADATA-80, METADATA-85, METADATA-90, METADATA-95 | deterministic copy, inference-off path, pattern selection, fact block | | METADATA-100, METADATA-105, METADATA-106, METADATA-107, METADATA-110, METADATA-115 | feat mapping, prompt storage, revision interface, Generate text control, failure triage | | PUBLISH-5, PUBLISH-10, PUBLISH-15, PUBLISH-20 | create sequence, draft rule, duplicate, stale | | PUBLISH-25, PUBLISH-30, PUBLISH-31, PUBLISH-35, PUBLISH-36, PUBLISH-37, PUBLISH-38 | success, failure, partial failure, triage | | PUBLISH-40, PUBLISH-45, PUBLISH-50, PUBLISH-55, PUBLISH-60 | images, lineup, meaning of published, payload, quantity | | SETTINGS-5, SETTINGS-10, SETTINGS-15, SETTINGS-20, SETTINGS-25, SETTINGS-30, SETTINGS-35 | store URL, auth, crypto, inference config, rates | | SETTINGS-40, SETTINGS-45, SETTINGS-50, SETTINGS-51, SETTINGS-55, SETTINGS-60, SETTINGS-65 | tests, taxonomy sync and anchor, create status | | SETTINGS-70, SETTINGS-75, SETTINGS-80, SETTINGS-85, SETTINGS-90 | vision cap, secret masking, test-woo, URL reject, flags | | APP-15, APP-20, APP-30, APP-35, APP-40, APP-45, APP-50, APP-55, APP-60, APP-65 | device draft, revisions, API base, envelope, health, logs, accessibility, redaction | | QUALITY-20, QUALITY-35, QUALITY-50, QUALITY-90, QUALITY-95, QUALITY-105, QUALITY-110, QUALITY-120, QUALITY-125 | M3 test bar and exit evidence | | OPS-40 | UAT host | ## 1. Review to ready Review is reached from a Photos-ready draft. The owner fills or confirms every field; each empty required field shows an inline nudge as they work, and the slab cannot reach `ready` until the full set is filled (`REVIEW-5`, `REVIEW-20`). Widths, sqft, and bdft are read-only client math (`REVIEW-30`); every other field stays editable until create (`REVIEW-40`). The owner declares one primary wood category and any secondary ones before Call 2 runs; the first selected is primary (`REVIEW-15`). Price is the bdft times the species rate; with no rate it starts empty and the owner must enter one; an override sticks (`REVIEW-25`). SKU is 3–24 alphanumeric and hyphen (`REVIEW-45`). Title and short_description are assembled deterministically and the description is written by the model or the server (`REVIEW-10`, `METADATA-80`); title and short_description warn past 60 and 160 characters (`REVIEW-50`). A picked id that vanished shows as no longer valid and is never silently swapped (`REVIEW-35`). ## 2. Inference assist Call 1 runs only when inference is enabled, after a calibrated draft uploads or on demand; it sends the clean processed photos at 1024 px long edge or less plus user metadata and the synced taxonomy, and returns suggestions constrained to those lists (`METADATA-35`, `METADATA-40`). At or above the threshold (default 0.7) a field pre-fills and stays editable; below it the field stays empty (`METADATA-45`). Typed values always win (`METADATA-50`). Free-text observations map to synced `feat-*` tags only (`METADATA-100`). Call 2 is user-triggered only and produces the long description (`METADATA-55`); the name and short description are already assembled from the primary wood category's patterns (`METADATA-80`, `METADATA-85`). Call 2 receives the processed photos, the review-confirmed metadata, the primary and secondary wood categories, the parent-category path, the dimension fact block, and brand/geo context; the model never invents a dimension (`METADATA-60`, `METADATA-65`, `METADATA-90`). The Generate text control appears only when content generation is enabled and the endpoint is reachable (`METADATA-110`). All generation is logged (`METADATA-66`). With inference off, the server produces the long description (`METADATA-70`). Prompts live in the database with all revisions, and the revision used is recorded with each call; the revision interface is REST only (`METADATA-105`, `METADATA-106`). Inference never blocks create and never auto-publishes (`METADATA-75`); a runtime failure offers Retry when recoverable or explains when it is not (`METADATA-115`). ## 3. Settings prerequisite Store URL is env-only, HTTPS, read-only (`SETTINGS-5`, `SETTINGS-10`); the settings API rejects a write to it (`SETTINGS-85`). Woo auth is a WordPress application password stored AES-GCM (`SETTINGS-15`, `SETTINGS-20`). `SLAB_AES_KEY` is env-only (`SETTINGS-25`). Inference URL and key are encrypted; flags, model, brand voice, and geo context are settings (`SETTINGS-30`); the flags default off (`SETTINGS-90`). Species rates are one flat value per synced leaf (`SETTINGS-35`). `woo_create_status` defaults to draft (`SETTINGS-65`). test-woo returns ok and detail, fails closed on missing credentials or non-HTTPS, and always resyncs taxonomy on success (`SETTINGS-80`, `SETTINGS-40`). test-inference returns ok, mode (stateful, stateless, or fail), vision_capable, and detail; fail blocks Call 2 only (`SETTINGS-45`). Taxonomy sync keeps only fig-* and feat-* tag families (`SETTINGS-51`), rebuilds in one transaction, keeps the previous cache on failure (`SETTINGS-50`), and bumps the anchor only on a real stored-subset change (`SETTINGS-55`). The client re-pulls when the anchor advances, and publish refreshes when the last sync is over an hour old (`SETTINGS-60`). ## 4. Publish The sequence validates the ready set, looks up the SKU and stops if it exists, refreshes taxonomy when stale, resolves categories, tags, and attributes, uploads the processed PNGs, calls `POST /products` per `docs/contracts/WOO-API.md`, then finalizes (`PUBLISH-5`). A `SLAB-UAT-*` SKU always creates a draft (`PUBLISH-10`). A duplicate SKU blocks create with edit-SKU or open-existing (`PUBLISH-15`). A stale value is a field-level error showing current options (`PUBLISH-20`). Success sets `woo_product_id`, purges photos, deletes the local row, and clears the device draft (`PUBLISH-25`, `APP-15`). Failure keeps photos, writes `sync_log`, and shows a plain message on the affected field with retry (`PUBLISH-30`); the failure is classified recoverable or unrecoverable (`PUBLISH-36`, `PUBLISH-37`, `PUBLISH-38`) and never shows a raw code (`PUBLISH-35`). Partial failure leaves orphaned media with a cleanup note (`PUBLISH-31`). Images upload as processed PNGs in photos-ready order with no cap (`PUBLISH-40`, `PUBLISH-45`). Published means the store create succeeded, not that it is live (`PUBLISH-50`). The payload is per `docs/contracts/WOO-API.md` (`PUBLISH-55`) and each product is one slab (`PUBLISH-60`). The payload carries an explicit slug: the sanitized product name plus the lowercased SKU (`PUBLISH-55`). ## 5. Acceptance - The full suite passes with inference disabled and asserts zero inference calls (`QUALITY-20`). - Integration tests cover success, error, duplicate SKU, stale field, and taxonomy anchor against a Woo mock (`QUALITY-35`). - UI and end-to-end tests run against a Compose stack with mocked Woo (`QUALITY-50`). - Vectors TV-8 (pricing) and TV-9 (thickness band) pass (`QUALITY-90`, `QUALITY-95`). - The M3 exit evidence is a real `SLAB-UAT-*` Woo draft matching the reviewed ready set, with inference off, plus test-woo and test-inference results (`QUALITY-110`). - No raw status code, stack trace, or internal code reaches the owner (`QUALITY-120`); encrypted credentials round-trip (`QUALITY-125`). - Dishonest proxies are rejected (`QUALITY-105`). ## 6. Out of scope Offline capture and U2Net matting (`CAPTURE-15`, `CAPTURE-165`), backup and restore (`OPS-30`, `OPS-35`), cross-browser end-to-end verification (`QUALITY-115`), and authentication for the prompt revision interface (`METADATA-107`). The V1 instrumentation work is out of M3.