docs: factual CONTENT-WOO/DATA-MODEL fixes + hybrid Phases 3-5
CONTENT-WOO: PNG media, fig-*/feat-* tags, five locked attributes, AGENTS-cited Woo safety. DATA-MODEL/OPENAPI drop server sheet prefs and PWA wording. ARCHITECTURE status reflects locked hybrid topology. IMPL Phases 3-5 rewritten for hybrid (all-photos@1024, confidence 0.7, no offline-era paths).
This commit is contained in:
@@ -14,7 +14,7 @@ When docs disagree, use this order until stale docs are rewritten:
|
||||
2. **`docs/ARCHITECTURE.md`** — hybrid topology, what-runs-where, secrets, status machine
|
||||
3. This **`AGENTS.md`** — hard rules for agents
|
||||
4. **`docs/DATA-MODEL.md`**, **`docs/OPENAPI.md`**, **`docs/CONTENT-WOO.md`**, **`docs/PROMPTS.md`**, **`docs/DEPLOYMENT.md`**
|
||||
5. **`docs/IMPL-PLAN.md`** — Phase 0 and rewritten Gate C / Phase 1–2 / Phase 6 sections are authoritative. Implement only Phase 0 plus sections marked rewritten. Do not implement deferred stubs (offline PWA, OCR, ruler) or any leftover server happy-path pipeline language.
|
||||
5. **`docs/IMPL-PLAN.md`** — Hybrid-aligned Phases 0–6 are authoritative. Phase 2 is a deferred stub only (offline PWA / OCR / ruler). Do not implement deferred stubs or any server happy-path measure/crop as SoT.
|
||||
6. **PRD / README** — product intent only; do **not** implement lines that contradict TECH-SPEC, ARCHITECTURE, or this file
|
||||
|
||||
Known stale / do-not-implement without rewrite:
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
# Architecture
|
||||
|
||||
Status: SPEC · 2026-08-27 · SlabUploader
|
||||
Locked so far: topology C (hybrid), swimlane, what-runs-where. Remaining sections TBD.
|
||||
Status: SPEC · hybrid topology locked at Gate A freeze (2026-08-31) · SlabUploader
|
||||
|
||||
Companion: PRD (root), TECH-SPEC-PIPELINE.md.
|
||||
Normative for hybrid split, swimlane, what-runs-where, secrets **why**, and status
|
||||
transitions. Ops depth lives in DEPLOYMENT. Schema enums live in DATA-MODEL.
|
||||
Agent-facing hard rules live in AGENTS.md (verbatim locks stay there).
|
||||
|
||||
Companion: TECH-SPEC-PIPELINE.md. PRD is historical intent only (see AGENTS precedence).
|
||||
|
||||
## 1. Topology (hybrid)
|
||||
|
||||
|
||||
+24
-20
@@ -75,15 +75,17 @@ Rebuilds the cache table (delete + insert, single transaction). Returns counts.
|
||||
Failure → `502 woo_error`; previous cache retained (never delete-then-fail).
|
||||
|
||||
### 2.3 Auto-assign taxonomy (FR26)
|
||||
- **Category**: species value is matched to a Woo category by name (case-insensitive,
|
||||
trimmed). Match → that category id. No match → the slab's `category_override`
|
||||
(user picks in review) or empty (Woo required-field validation will surface it).
|
||||
- **Tags**: `[character]` plus optional `[species]` if present as a tag.
|
||||
Call 1 feat-* observations are mapped to Woo feat-* tags (e.g., Crack/Check,
|
||||
Resin Ready). WooCommerce is authoritative for tag definitions.
|
||||
- **Attributes**: species/character/length/thickness as product attributes if the
|
||||
corresponding Woo attributes exist in the cache (by name). Missing attributes are
|
||||
skipped, not created (v1: no attribute creation).
|
||||
- **Categories**: species leaf category (1 required) plus wood-category leaf ids (1+).
|
||||
Match by name against the synced Woo category cache (case-insensitive, trimmed).
|
||||
No match → user override in review, or empty (Woo required-field validation surfaces it).
|
||||
- **Tags**: `fig-*` only for figure tags (1+ required) and `feat-*` only for feature tags
|
||||
(0+). Call 1 free-text observations (character / inclusions / voids / checks) map to
|
||||
existing Woo `feat-*` tags. Do not invent generic character or species product tags.
|
||||
WooCommerce is authoritative for tag definitions.
|
||||
- **Attributes**: the five locked Woo attributes only — Edge Type, Figure, Grade,
|
||||
Thickness, Moisture — using term ids from the cache. Do not publish species, character,
|
||||
length, or free-text thickness as product attributes. Missing attributes are skipped,
|
||||
not created (v1: no attribute creation).
|
||||
- Every assignment is overridable in the review screen (FR26).
|
||||
|
||||
### 2.4 Product create payload (FR27)
|
||||
@@ -98,7 +100,7 @@ Failure → `502 woo_error`; previous cache retained (never delete-then-fail).
|
||||
"description": "{description}",
|
||||
"short_description": "{short_title}",
|
||||
"categories": [ { "id": <species category id> } ],
|
||||
"tags": [ { "id": <char tag id> }, … ],
|
||||
"tags": [ { "id": <fig-* tag id> }, { "id": <feat-* tag id> }, … ],
|
||||
"images": [
|
||||
{ "src": "<data URL or pre-uploaded attachment URL>", "alt": "{species} {character} slab" }
|
||||
],
|
||||
@@ -110,15 +112,17 @@ Failure → `502 woo_error`; previous cache retained (never delete-then-fail).
|
||||
```
|
||||
**Image upload strategy** (Woo v3): `images[].src` accepts a URL or a data URL.
|
||||
For reliability the server:
|
||||
1. For each customer-facing (inventory, normalized) photo in `seq` order:
|
||||
`POST /media` with the JPEG bytes → get attachment `source_url`.
|
||||
2. Reference those `source_url` values in `images` (≤5, per PRD 1–5 inventory photos).
|
||||
3. Calibration photos are excluded (FR2).
|
||||
1. For each customer-facing inventory photo in `seq` order (processed transparent PNGs
|
||||
from the client TECH-SPEC path): `POST /media` with the **PNG bytes** → get attachment
|
||||
`source_url`. Woo accepts `image/*`; keep alpha. Do not re-encode to JPEG and drop alpha.
|
||||
2. Reference those `source_url` values in `images` (≤5 inventory photos).
|
||||
3. Only `kind=inventory` photos. Calibration photos do not exist in this design.
|
||||
|
||||
**Status** comes from Settings key **`woo_create_status`** (`draft` | `publish`, default
|
||||
**`draft`**). UAT on PROD uses Woo **draft** plus SKU prefix `SLAB-UAT-*` (hard rule:
|
||||
`SLAB-UAT-*` always creates as Woo draft even if Settings say publish). Flip to
|
||||
`publish` only for intentional live inventory after Ty review. Do not conflate with
|
||||
**`draft`**). Woo **safety policy** (UAT draft default, `SLAB-UAT-*` force draft even when
|
||||
Settings say publish, no edit-same-SKU, purge originals + processed images after successful
|
||||
publish) is owned by **AGENTS.md §5**. This file owns payload shape and publish sequence
|
||||
only. Do not diverge from AGENTS on force-draft. Do not conflate Woo create status with
|
||||
slab lifecycle status `published` (means Woo create succeeded locally).
|
||||
|
||||
### 2.5 Dedupe & idempotency (FR24a)
|
||||
@@ -142,9 +146,9 @@ Before create: `GET /products?sku={sku}`.
|
||||
2. dedupe by SKU (GET /products?sku=) → 409 duplicate_sku if exists
|
||||
3. (re)sync taxonomy if cache older than 1h → best-effort; use existing cache on fail
|
||||
4. resolve category/tags/attributes (auto-assign + overrides)
|
||||
5. upload normalized inventory images → media → source_urls
|
||||
6. POST /products (status=woo_create_status) → woo_product_id
|
||||
7. write sync_log(success), set slab published, purge images
|
||||
5. upload processed PNG inventory images → media → source_urls
|
||||
6. POST /products (status per AGENTS §5 + woo_create_status) → woo_product_id
|
||||
7. write sync_log(success), set slab published, purge originals + processed images
|
||||
on any failure at 2–6: write sync_log(failed), slab=failed, (images retained for retry)
|
||||
```
|
||||
|
||||
|
||||
+10
-4
@@ -4,7 +4,7 @@ Status: SPEC · 2026-08-27 · SlabUploader
|
||||
Storage: single SQLite file. Schema portable to Postgres.
|
||||
|
||||
Conventions:
|
||||
- IDs: client-generated UUIDv4 for slabs so the PWA can reference a slab before it exists server-side.
|
||||
- IDs: client-generated UUIDv4 for slabs so the SvelteKit client can reference a slab before it exists server-side.
|
||||
- Timestamps: UTC ISO-8601 TEXT.
|
||||
- Soft state via status column; no hard deletes for slabs (audit).
|
||||
- Money: float64 USD, rounded half-up to cents at write.
|
||||
@@ -174,20 +174,26 @@ authoritative source for tag definitions; this table caches synced Woo tags.
|
||||
| `value_enc` | BLOB | AES-GCM ciphertext |
|
||||
| `updated_at` | TEXT | |
|
||||
|
||||
Keys:
|
||||
Keys (server settings; secrets encrypted at rest):
|
||||
- `woo_base_url`, `woo_consumer_key`, `woo_consumer_secret`
|
||||
- `inference_base_url`, `inference_api_key`, `inference_model`
|
||||
- `inference_enabled`, `content_llm_enabled`
|
||||
- `brand_voice`, `geo_context`
|
||||
- `woo_create_status` ('draft' | 'publish'), default `draft` — Woo product create status; not slab lifecycle
|
||||
- `woo_create_status` ('draft' | 'publish'), default `draft` — Woo product create status key only; safety policy lives in AGENTS.md §5
|
||||
- `aspect_ratio` ('3:4'), `output_px` (1600), `output_px_min` (1600), `fill_target` (0.80)
|
||||
- `user_sensitivity`, `user_edge_offset`, `user_feather`, `user_sheet_mode`
|
||||
|
||||
Sheet/slider prefs (`sheet_mode`, sensitivity, edge offset, feather) are **not** server
|
||||
settings keys in POC. Client localStorage is source of truth (AGENTS §4 / ARCHITECTURE §5).
|
||||
Optional server sync of those prefs is out of scope for POC.
|
||||
|
||||
**Prompt files** — not in the settings table. Stored as text files in
|
||||
`/data/prompts/` (server volume). Read fresh on each invocation. Default
|
||||
prompts shipped with the app; owner edits directly. A reset-to-default script
|
||||
restores originals.
|
||||
|
||||
This table is the ciphertext **key inventory** and schema only. The never-browser /
|
||||
AES-GCM / `SLAB_AES_KEY` env policy lives in AGENTS.md §4; flow lives in ARCHITECTURE §5.
|
||||
|
||||
AES master key is an env var (`SLAB_AES_KEY`, 32 bytes base64). Never in the DB.
|
||||
Each `value_enc` = `nonce(12) || ciphertext`.
|
||||
|
||||
|
||||
+57
-55
@@ -1,11 +1,9 @@
|
||||
# Implementation Plan
|
||||
|
||||
Status: SPEC · Gate A freeze 2026-08-31 · hybrid rewrite pass 2026-09-01 · SlabUploader
|
||||
Status: SPEC · Gate A freeze 2026-08-31 · hybrid rewrite complete 2026-09-01 · SlabUploader
|
||||
|
||||
Phase 0 and the Gate C / Phase 1–2 / Phase 6 sections below are authoritative for hybrid
|
||||
topology. Phases 3–5 still need a full hybrid rewrite in a later docs commit; until then
|
||||
implement only Phase 0 plus sections marked rewritten here. Do not implement deferred
|
||||
stubs (offline PWA, OCR, ruler) or any server happy-path measure/crop as SoT.
|
||||
Phases 0–6 below are hybrid-aligned. Phase 2 remains a deferred stub only. Do not
|
||||
implement offline PWA, OCR, ruler, or any server happy-path measure/crop as SoT.
|
||||
|
||||
The build plan a professional (or a fresh Hermes session) executes against. Each phase
|
||||
has: goal, deliverables, acceptance criteria (testable), and exit gate. Ordering is by
|
||||
@@ -149,50 +147,57 @@ No airplane-mode acceptance. No OCR or ruler exit gate in POC.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Frontend: enrich, review, publish UI
|
||||
## Phase 3 — Frontend: enrich, review, publish UI (rewritten)
|
||||
|
||||
> **Partial hybrid rewrite pending (docs commit 3).** Goal and intent below stay valid.
|
||||
> Do not reintroduce offline capture, server measure/crop, or a `processing` status.
|
||||
> Prefer AGENTS + ARCHITECTURE + OPENAPI over any leftover offline-era wording.
|
||||
|
||||
Goal: the enriched review screen and publish action, wired to Phase 1 API.
|
||||
Goal: online review + publish UI on top of Gate C calibrated drafts. Hybrid only.
|
||||
Client already owns mask/numbers/PNGs. This phase does not re-measure on the server.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- Review screen: all fields editable (dimensions, species/character with confidence
|
||||
+ manual override, price with recommendation, content with "Generate text" when
|
||||
inference is on, client-processed PNGs).
|
||||
- Species/character inference UI (calls server; shows confidence; manual confirm below
|
||||
threshold). Call 1 uses all inventory photos @1024 when inference is enabled.
|
||||
- Publish button (online-only), status polling, success/failure states, error detail.
|
||||
- Settings UI: Woo creds + test, inference endpoint + test (vision check),
|
||||
pricing rules editor, brand voice/GEO. Prompts are server files, not UI settings.
|
||||
- Review screen after calibrated upload: all fields editable (length, thickness, SKU,
|
||||
widths/sqft/bdft shown as client-computed with manual override paths, species and
|
||||
wood categories, five attributes, fig-*/feat-* tags, price with species $/bdft
|
||||
recommendation, title/short/description).
|
||||
- Show client-processed transparent PNGs (and originals while retained). No server
|
||||
re-crop UI as SoT.
|
||||
- Inference UI (only meaningful after Gate C and when `inference_enabled`): Call 1
|
||||
results with confidence; manual confirm required below threshold **0.7**
|
||||
(configurable). "Generate text" triggers Call 2; never auto.
|
||||
- Publish button (online-only), poll `publishing` → `published` | `failed`, surface
|
||||
error detail from sync_log.
|
||||
- Settings UI: Woo creds + test, inference endpoint + test (vision check), pricing
|
||||
rules editor, brand voice/GEO, `woo_create_status`. Sheet/slider prefs stay in
|
||||
client localStorage. Prompts are server files, not UI settings.
|
||||
- Secrets never appear in GET settings responses (masked `*_configured` only).
|
||||
|
||||
Acceptance:
|
||||
|
||||
- Full round-trip in browser: capture → upload → review → edit → publish → local
|
||||
`published` (against a Woo sandbox/mock in tests; against real store in Phase 6).
|
||||
- Inference disabled → review screen fully functional with manual species/character.
|
||||
- Every field is editable and the override persists (asserted in a test).
|
||||
- Browser round-trip: online capture → mask/axis confirm → calibrated upload →
|
||||
review → edit → publish → local `published` (Woo mock in tests; real store Phase 6).
|
||||
- Inference OFF → full manual taxonomy + content path works; no inference network calls.
|
||||
- Field overrides persist across poll/refresh (asserted).
|
||||
- No offline/IndexedDB requirement. No OCR/ruler UI.
|
||||
|
||||
Exit gate: Ty publishes a test slab to the real store as a **Woo draft** (`SLAB-UAT-*`) product.
|
||||
Exit gate: Ty publishes a test slab to the real store as a **Woo draft** (`SLAB-UAT-*`).
|
||||
(Gate A lock: not pending/published for UAT.)
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — WooCommerce integration (real)
|
||||
## Phase 4 — WooCommerce integration (rewritten)
|
||||
|
||||
> **Partial hybrid rewrite pending (docs commit 3).** Payload and safety locks already
|
||||
> match AGENTS. Keep `woo_create_status` + `SLAB-UAT-*` force-draft. No server happy-path
|
||||
> image pipeline as SoT.
|
||||
|
||||
Goal: production Woo sync, taxonomy, dedupe, logging (FR24–28).
|
||||
Goal: production Woo sync, taxonomy, dedupe, logging. Browser never calls Woo.
|
||||
Media bytes are client-processed **PNGs**. Safety policy from AGENTS §5.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- Woo client (httpx, Basic auth, timeouts), taxonomy sync, auto-assign, media upload,
|
||||
product create via `woo_create_status` (default **draft**; `SLAB-UAT-*` forces draft),
|
||||
dedupe, sync_log.
|
||||
- Woo client (httpx, Basic auth, timeouts), taxonomy sync into cache tables, auto-assign
|
||||
per CONTENT-WOO §2.3 (categories + five attributes + fig-*/feat-* tags only).
|
||||
- Media upload of processed PNG inventory photos; product create via `woo_create_status`
|
||||
(default **draft**). If SKU matches `SLAB-UAT-*`, force Woo **draft** even when
|
||||
Settings say publish.
|
||||
- Dedupe by SKU before create; `409 duplicate_sku`; no edit-same-SKU path in MVP.
|
||||
- `sync_log` with payload_hash; on success set local `published`, purge originals +
|
||||
processed images on server.
|
||||
- `POST /api/admin/taxonomy/sync` against the real store.
|
||||
- Integration tests against a Woo mock (respx) for success + error + duplicate paths.
|
||||
- Partial-failure handling (orphaned media noted, per CONTENT-WOO §2.6).
|
||||
@@ -200,8 +205,8 @@ Deliverables:
|
||||
Acceptance:
|
||||
|
||||
- Real UAT publish: product appears in store admin as **draft** under `SLAB-UAT-*`,
|
||||
correct SKU/price/images/category/tags; `woo_product_id` stored; `sync_log` written
|
||||
with payload_hash.
|
||||
correct SKU/price/PNG images/category/tags/attributes; `woo_product_id` stored;
|
||||
`sync_log` written with payload_hash.
|
||||
- Duplicate SKU publish → 409, no second product created.
|
||||
- Woo error (bad creds / 500) → slab `failed` with detail; retry path works.
|
||||
- All Woo integration tests green (mock + one live smoke).
|
||||
@@ -210,33 +215,30 @@ Exit gate: Ty verifies a real **Woo draft** `SLAB-UAT-*` product in the store is
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 — Inference (vision + optional content)
|
||||
## Phase 5 — Inference (vision + optional content) (rewritten)
|
||||
|
||||
> **Partial hybrid rewrite pending (docs commit 3).** Sequencing lock stands: inference
|
||||
> OFF until Gate C is green; Call 1/2 still inside POC after Gate C. Call 1 = all photos
|
||||
> @1024 (not top-down-only). Confidence threshold 0.7 (configurable) lives here.
|
||||
|
||||
Goal: scoped, toggleable inference with guardrails. Starts only after Gate C is green.
|
||||
Goal: scoped, toggleable inference **after Gate C is green**, still inside POC.
|
||||
Does not gate publish. Full suite must pass with inference OFF.
|
||||
|
||||
Deliverables:
|
||||
|
||||
- Vision wrapper: species/character (and related taxonomy) from **all inventory photos**
|
||||
downscaled to 1024 via the configurable OpenAI-compatible endpoint; model constrained
|
||||
to Woo taxonomy cache; returns confidence (threshold **0.7**, configurable); logs
|
||||
request/response.
|
||||
- Content wrapper: Call 2 reads `prompts/call2.txt`; LLM writes prose only,
|
||||
dimensions injected by deterministic templates. See `docs/PROMPTS.md`.
|
||||
- `test-inference` endpoint (vision capability check).
|
||||
- All inference code behind feature flags; suite passes with everything OFF.
|
||||
- Call 1 (vision) proxy: **all inventory photos** downscaled to 1024 + Woo taxonomy
|
||||
snapshot + user metadata; OpenAI-compatible endpoint; model constrained to cached
|
||||
taxonomy; confidence threshold **0.7** (configurable; relocate from older PRD FR22a).
|
||||
Auto-run on calibrated create only if `inference_enabled`. Not top-down-only.
|
||||
- Call 2 (text) proxy: never auto. User taps Generate text. LLM prose only; templates
|
||||
inject deterministic numbers. See `docs/PROMPTS.md`.
|
||||
- `test-inference` endpoint (vision capability check) before Call 2 is allowed.
|
||||
- Feature flags; `inference_log` audit rows; prompt files read fresh each call.
|
||||
- No numeric/dimension invention by the LLM. LoRA deferred.
|
||||
|
||||
Acceptance:
|
||||
|
||||
- With a local vision model configured: species/character suggestion appears with
|
||||
confidence; low confidence → manual confirm required.
|
||||
- With inference OFF: full app works, tests green (explicit test asserts no network
|
||||
calls to the inference endpoint).
|
||||
- Inference payloads stored for audit (asserted present after a call).
|
||||
- Call 1 prompt file edits survive server restart (read fresh each invocation).
|
||||
- Local vision model configured: taxonomy suggestions appear with confidence; below
|
||||
0.7 → manual confirm required.
|
||||
- Inference OFF: app works end-to-end; tests assert zero calls to the inference endpoint.
|
||||
- Audit payloads present after a call; prompt file edits apply without server restart.
|
||||
- Gate C path remains green with inference OFF.
|
||||
|
||||
Exit gate: Ty runs species detection on 3 real slabs; results acceptable or manually
|
||||
corrected (that is the design).
|
||||
|
||||
+2
-3
@@ -128,11 +128,10 @@ the call returns. WooCommerce is the authoritative source for `feat-*` definitio
|
||||
"brand_voice": "...", "geo_context": "...",
|
||||
"woo_create_status": "draft",
|
||||
"aspect_ratio": "3:4", "output_px": 1600, "output_px_min": 1600,
|
||||
"fill_target": 0.80,
|
||||
"user_sensitivity": 0.5, "user_edge_offset": 0, "user_feather": 1,
|
||||
"user_sheet_mode": "auto" }
|
||||
"fill_target": 0.80 }
|
||||
```
|
||||
Secrets (keys) are never returned. Only a `*_configured` boolean.
|
||||
Sheet/slider prefs are client localStorage only in POC (not in SettingsView).
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user