Files
Ty b166e796ad tools(docs): require citations in citing docs
Two checks were added to catch drift between the point of record and the
docs that cite it.

- Check 11: a capability or contract doc must declare its IDs in a
  Requirements impact table, and may cite only those.
- Check 12: a section that makes a behavior claim must cite an ID in that
  section. External-shape sections are exempt.

CAPTURE.md and CREATE.md gained the impact-table rows the first check
requires. check_coverage is unchanged.
2026-09-19 13:17:37 -07:00

123 lines
8.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 |
| CAPTURE-15, CAPTURE-165, OPS-30, OPS-35, QUALITY-115, METADATA-107 | out of scope |
| 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.