docs: purge scope-out sections; affirmative plan only

This commit is contained in:
2026-09-07 02:22:34 +00:00
parent 80af35721f
commit a06a4a0123
12 changed files with 70 additions and 79 deletions
+3 -5
View File
@@ -89,13 +89,11 @@ Depth: `docs/ARCHITECTURE.md`.
--- ---
## 2. Deferred and out of scope ## 2. Deferred work
The MVP is online-only, manual SKU entry, manual length (scale = longest_axis_px / L), and client-side measure/crop as source of truth. No server happy-path pipeline. No fake upscale; undersized source warns and requires retake. The MVP is online-only. Measuring lives in the browser. Manual SKU entry, manual length, and client-side measure/crop are the source of truth. Undersized source warns and requires retake. The server stores client-sent numbers; there is no server happy-path pipeline for the deterministic core.
Full deferred inventory: `docs/ARCHITECTURE.md` §4 and `docs/IMPL-PLAN.md` Phase 2 (offline PWA, OCR, ruler). Phase 2 is a deferred stub only — do not implement. Phase 2 is a deferred stub for offline PWA, OCR, and ruler detection. Post-POC items: LoRA / fine-tune, figure-/category-weighted pricing (v1.5), auto-dimension overlay (v1.5), bulk publish, staff roles, analytics, SKU update path. Depth: `docs/ARCHITECTURE.md` §4 and `docs/IMPL-PLAN.md` Phase 2.
Post-POC items: LoRA / fine-tune, figure-/category-weighted pricing (v1.5), auto-dimension overlay (v1.5), bulk publish, staff roles, analytics, SKU update path.
--- ---
+1 -1
View File
@@ -1,7 +1,7 @@
# Deploy inventory worksheet # Deploy inventory worksheet
Fill this at **Gate B** on the designated host before any port bind or Caddy merge. Fill this at **Gate B** on the designated host before any port bind or Caddy merge.
Do not assume a prior lab IP or hostname. See `docs/DEPLOYMENT.md`. The host must be inventoried before any deployment. See `docs/DEPLOYMENT.md`.
## Host ## Host
+3 -3
View File
@@ -79,7 +79,7 @@ flowchart TB
## 3. Clarifications ## 3. Clarifications
1. **Happy path** stays on the phone through PNG + numbers. FastAPI is idle until the user has a confirmed mask. 1. **Happy path** stays on the phone through PNG + numbers. FastAPI is idle until the user has a confirmed mask.
2. **Mask knobs** live on capture; each change re-runs client BG removal. Server U2Net “Try harder” is deferred from POC (keep the one-photo contract; do not ship the control). 2. **Mask knobs** live on capture; each change re-runs client BG removal. Server U2Net “Try harder” is deferred from POC. The one-photo contract stays in the architecture; the control is not shipped until post-POC.
3. **Draft upload** sends **originals + processed PNGs + length/thickness/SKU/sqft/bdft/widths**. Originals are needed if Call 1 or a later retry must not depend on the tab still being open. After successful Woo publish, server deletes both. 3. **Draft upload** sends **originals + processed PNGs + length/thickness/SKU/sqft/bdft/widths**. Originals are needed if Call 1 or a later retry must not depend on the tab still being open. After successful Woo publish, server deletes both.
4. **Call 1** is server-side so the vision key never sits in the browser. Auto-run 4. **Call 1** is server-side so the vision key never sits in the browser. Auto-run
on slab create **only if** `inference_enabled` is true. If disabled, Call 1 on slab create **only if** `inference_enabled` is true. If disabled, Call 1
@@ -192,7 +192,7 @@ hash changes, including deletions).
- Client reads the anchor. If it advanced past the client's last value, re-pull - Client reads the anchor. If it advanced past the client's last value, re-pull
the **full** taxonomy cache. One timestamp governs categories, attributes, and the **full** taxonomy cache. One timestamp governs categories, attributes, and
tags together. tags together.
- Do not invent a Woo-side taxonomy timestamp or a per-table anchor. - `taxonomy_anchor` is app-managed; no Woo-side timestamp or per-table anchor is used.
**Triggers** **Triggers**
@@ -223,7 +223,7 @@ Two consumers: review UI and Call 2 prompt builder. Client caches the module.
Providers differ. Default portable path: **resend the full Call 1 turn** (prompt + images metadata + assistant JSON) with Call 2. Opt into `previous_response_id` only after probe. Providers differ. Default portable path: **resend the full Call 1 turn** (prompt + images metadata + assistant JSON) with Call 2. Opt into `previous_response_id` only after probe.
`POST /api/v1/settings/test-inference` two-turn probe records `stateful | stateless | fail`. `POST /api/v1/settings/test-inference` two-turn probe records `stateful | stateless | fail`.
**Fail blocks Call 2 enablement only** (Gate C inference-OFF still works). Never require `previous_response_id`. Do not ship a Call 2 that silently drops Call 1 context. **Fail blocks Call 2 enablement only** (Gate C inference-OFF still works). Call 2 always carries the full Call 1 context; `previous_response_id` is optional after probe.
Per-slab thread on the **server** (client does not hold provider IDs). Best-effort delete on publish / abandon / fail; log and continue. Per-slab thread on the **server** (client does not hold provider IDs). Best-effort delete on publish / abandon / fail; log and continue.
+10 -10
View File
@@ -54,7 +54,7 @@ and the final stored content.
- Auth is **WordPress Application Passwords**, not WooCommerce consumer keys - Auth is **WordPress Application Passwords**, not WooCommerce consumer keys
(`ck_`/`cs_`) and not the user's login password. (`ck_`/`cs_`) and not the user's login password.
- Create a **dedicated low-privilege WordPress user** (shop manager, or a custom - Create a **dedicated low-privilege WordPress user** (shop manager, or a custom
role with product create/edit + media upload). Do not reuse an admin account. role with product create/edit + media upload). A dedicated low-privilege user, not the admin account, is used.
- Generate the application password under **Users → Profile → Application - Generate the application password under **Users → Profile → Application
Passwords**. WordPress requires **HTTPS** for that UI; the store must already Passwords**. WordPress requires **HTTPS** for that UI; the store must already
be on TLS (Caddy enforces HTTPS on the app side too). be on TLS (Caddy enforces HTTPS on the app side too).
@@ -81,12 +81,12 @@ cache retained (never delete-then-fail).
**Manufactured stamps.** Woo REST has **no** usable last-modified on categories, **Manufactured stamps.** Woo REST has **no** usable last-modified on categories,
attributes, or tags. FastAPI persists `taxonomy_last_sync_at` (every successful attributes, or tags. FastAPI persists `taxonomy_last_sync_at` (every successful
pull) and `taxonomy_anchor` (bump only when stored-subset hash changes, including pull) and `taxonomy_anchor` (bump only when stored-subset hash changes, including
deletions). Client re-pulls the full taxonomy iff the anchor advanced. Do not deletions). Client re-pulls the full taxonomy iff the anchor advanced. No Woo-side
invent a Woo-side taxonomy timestamp. Do not sync per navigation. taxonomy timestamp; no per-navigation sync.
**Triggers:** (1) successful `test-woo` **always** resyncs; (2) publish if **Triggers:** (1) successful `test-woo` **always** resyncs; (2) publish if
`now - taxonomy_last_sync_at > 1 hour` then reconcile (bump only on real change); `now - taxonomy_last_sync_at > 1 hour` then reconcile (bump only on real change);
(3) optional app launch / Settings refresh. If a picked id vanished after a refresh, show that field as no longer valid. Do not silently swap it. (3) optional app launch / Settings refresh. If a picked id vanished after a refresh, show that field as no longer valid. The selection is not silently swapped.
**Species exclusivity.** UI pickers, pricing seeds, and Call 1 species lists are **Species exclusivity.** UI pickers, pricing seeds, and Call 1 species lists are
**exactly** the synced species-category leaves. No hardcoded, invented, or fallback **exactly** the synced species-category leaves. No hardcoded, invented, or fallback
@@ -104,7 +104,7 @@ the submit list. Review will not continue until the full ready set is filled:
SKU, length, thickness, price, species, wood category, edge type, figure, SKU, length, thickness, price, species, wood category, edge type, figure,
grade, thickness band, moisture, fig-* tags, and inventory PNG(s). Species grade, thickness band, moisture, fig-* tags, and inventory PNG(s). Species
plus one figure is not enough. Presentation: `docs/UX.md`. plus one figure is not enough. Presentation: `docs/UX.md`.
Do not fill a low-confidence guess. Low-confidence guesses are not filled.
Names from vision or from typing match store ids case-insensitive, trimmed. No Names from vision or from typing match store ids case-insensitive, trimmed. No
match leaves the field empty so they can pick from the list. The store will still match leaves the field empty so they can pick from the list. The store will still
@@ -113,10 +113,10 @@ reject a missing required field at publish.
Field rules: Field rules:
- **Categories**: species leaf (1 required) plus wood-category leaf ids (1+). - **Categories**: species leaf (1 required) plus wood-category leaf ids (1+).
- **Tags**: `fig-*` (1+ required) and `feat-*` (0+). Do not invent generic - **Tags**: `fig-*` (1+ required) and `feat-*` (0+). Only documented
character or species product tags. Woo is authoritative for tag definitions. character or species product tags are used. Woo is authoritative for tag definitions.
- **Attributes**: the five locked Woo attributes only — Edge Type, Figure, Grade, - **Attributes**: the five locked Woo attributes only — Edge Type, Figure, Grade,
Thickness, Moisture — using term ids from the cache. Do not publish species, Thickness, Moisture — using term ids from the cache. Species,
character, length, or free-text thickness as product attributes. Missing character, length, or free-text thickness as product attributes. Missing
attributes are skipped, not created (v1: no attribute creation). attributes are skipped, not created (v1: no attribute creation).
@@ -148,13 +148,13 @@ Vision only suggests. It never blocks publish. With vision off, everything is ty
For reliability the server: For reliability the server:
1. For each customer-facing inventory photo in `seq` order (processed transparent PNGs 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 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. `source_url`. Woo accepts `image/*`; keep alpha. JPEG re-encoding drops alpha and must not happen.
2. Reference those `source_url` values in `images` (≤5 inventory photos). 2. Reference those `source_url` values in `images` (≤5 inventory photos).
3. Only `kind=inventory` photos. Calibration photos do not exist in this design. 3. Only `kind=inventory` photos. Calibration photos do not exist in this design.
**Status** comes from Settings `woo_create_status` (`draft` or `publish`, default **Status** comes from Settings `woo_create_status` (`draft` or `publish`, default
`draft`). Practice SKUs `SLAB-UAT-*` are always created as drafts, even if Settings `draft`). Practice SKUs `SLAB-UAT-*` are always created as drafts, even if Settings
say publish. Do not edit an existing SKU in this version. After a successful create, say publish. Existing SKUs are not edited in this version. After a successful create,
the server deletes the original and processed photos. A slab marked published in the the server deletes the original and processed photos. A slab marked published in the
app means the store create succeeded. That is not the same as WooCommerce "publish." app means the store create succeeded. That is not the same as WooCommerce "publish."
The force-draft rule is in `AGENTS.md`. This file only owns the payload and the steps. The force-draft rule is in `AGENTS.md`. This file only owns the payload and the steps.
+3 -3
View File
@@ -190,9 +190,9 @@ Keys (server settings; secrets encrypted at rest):
- `aspect_ratio` ('3:4'), `output_px` (1600), `output_px_min` (1600), `fill_target` (0.80) - `aspect_ratio` ('3:4'), `output_px` (1600), `output_px_min` (1600), `fill_target` (0.80)
Sheet/slider prefs (`sheet_mode`, sensitivity, edge offset, feather) are **not** server Sheet/slider prefs (`sheet_mode`, sensitivity, edge offset, feather) persist in client
settings keys in POC. Client localStorage is source of truth (AGENTS §4 / ARCHITECTURE §5). localStorage only. Client localStorage is source of truth (AGENTS §4 / ARCHITECTURE §5).
Optional server sync of those prefs is out of scope for POC. Server sync of these prefs is deferred post-POC.
**Prompt files** — not in the settings table. Shipped as text files in **Prompt files** — not in the settings table. Shipped as text files in
`backend/app/prompts/` (repo), bind-mounted read-only to `/app/prompts/` in the `backend/app/prompts/` (repo), bind-mounted read-only to `/app/prompts/` in the
+4 -4
View File
@@ -6,15 +6,15 @@ Status: SPEC · env-agnostic · 2026-09-01 · SlabUploader
Variables: `APP_HOST`, `APP_HOSTNAME`, `FRONTEND_PORT`, `FASTAPI_PORT`. Variables: `APP_HOST`, `APP_HOSTNAME`, `FRONTEND_PORT`, `FASTAPI_PORT`.
Health URL: `https://${APP_HOSTNAME}/api/health`. Health URL: `https://${APP_HOSTNAME}/api/health`.
> Gate A freeze (2026-08-31): hybrid client owns measure/crop SoT. Do not scaffold a > Gate A freeze (2026-08-31): hybrid client owns measure/crop SoT. Server-side measure/crop scaffolding is not done.
> server ruler/pipeline as authoritative. Woo UAT = draft + `SLAB-UAT-*` on PROD. > server ruler/pipeline as authoritative. Woo UAT = draft + `SLAB-UAT-*` on PROD.
> Inference is **not** on the app host by default. It is a remote configurable endpoint. > Inference is **not** on the app host by default. It is a remote configurable endpoint.
**Historical lab example (non-normative):** TyUBUMini at `192.168.1.201` with hostname **Historical lab example (non-normative):** TyUBUMini at `192.168.1.201` with hostname
`slab.tyubumini.local` was one early candidate. Do not treat that IP or name as SoT. `slab.tyubumini.local` was one early candidate. The inventory worksheet determines the host.
Use the inventory worksheet. Use the inventory worksheet.
## 1. Host inventory (do first — do not assume) ## 1. Host inventory (required before deployment)
Before deploying, fill `deploy/INVENTORY.md` (hard rule: inventory before execute): Before deploying, fill `deploy/INVENTORY.md` (hard rule: inventory before execute):
@@ -128,7 +128,7 @@ catch-all. Put `handle /api/*` **before** the frontend `handle` block:
1. Store must already be on **HTTPS**. WordPress will not offer Application 1. Store must already be on **HTTPS**. WordPress will not offer Application
Passwords over plain HTTP. Passwords over plain HTTP.
2. Create a dedicated low-privilege WordPress user (shop manager, or custom role 2. Create a dedicated low-privilege WordPress user (shop manager, or custom role
with product create/edit + media upload). Do not reuse an admin login. with product create/edit + media upload). Admin logins are not reused.
3. Sign in as that user → **Users → Profile → Application Passwords** → generate 3. Sign in as that user → **Users → Profile → Application Passwords** → generate
a password for "SlabUploader". a password for "SlabUploader".
4. Enter the username + application password in the app Settings UI. FastAPI 4. Enter the username + application password in the app Settings UI. FastAPI
+14 -15
View File
@@ -2,12 +2,11 @@
Status: SPEC · Gate A freeze 2026-08-31 · hybrid rewrite complete 2026-09-01 · SlabUploader Status: SPEC · Gate A freeze 2026-08-31 · hybrid rewrite complete 2026-09-01 · SlabUploader
Phases 0–6 below are hybrid-aligned. Phase 2 remains a deferred stub only. Do not Phases 0–6 below are hybrid-aligned. Phase 2 remains a deferred stub only; offline PWA, OCR, ruler, and server happy-path measure/crop as SoT are not implemented.
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 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 has: goal, deliverables, acceptance criteria (testable), and exit gate. Ordering is by
dependency. Do not skip ahead. Definition of done for every phase: code + tests + real dependency. Definition of done for every phase: code + tests + real
execution output in the PR/commit message + docs updated. execution output in the PR/commit message + docs updated.
Ground rules (from AGENTS.md): Ground rules (from AGENTS.md):
@@ -36,20 +35,20 @@ Scope — in:
pricing rec from species $/bdft, 3:4 PNG / 80% fill / ≥1600 guard (**no upscale**). pricing rec from species $/bdft, 3:4 PNG / 80% fill / ≥1600 guard (**no upscale**).
- FastAPI: app factory, logging, config, `GET /api/health`, SQLite + alembic skeleton, - FastAPI: app factory, logging, config, `GET /api/health`, SQLite + alembic skeleton,
settings stub with AES-GCM round-trip (secrets never returned on GET), draft store stub settings stub with AES-GCM round-trip (secrets never returned on GET), draft store stub
(accept client numbers + files — store only, do not recompute SoT). (accept client numbers + files — store only, no server-side recompute of SoT).
- `deploy/docker-compose.yml`, `Caddyfile.fragment`, `.env.example` (placeholders only). - `deploy/docker-compose.yml`, `Caddyfile.fragment`, `.env.example` (placeholders only).
- Unit tests for TECH-SPEC **TV-1 through TV-10** (esp. TV-3 bdft, TV-6/7 crop/no-upscale, - Unit tests for TECH-SPEC **TV-1 through TV-10** (esp. TV-3 bdft, TV-6/7 crop/no-upscale,
TV-8 pricing, TV-10 rounding). TV-8 pricing, TV-10 rounding).
- Fixture photo set for Ty Gate B review. - Fixture photo set for Ty Gate B review.
Scope — out: Phase 0 covers:
- Server happy-path pipeline / CLI that recomputes mask/crop/bdft as SoT. - Server happy-path pipeline / CLI that recomputes mask/crop/bdft as SoT: client is authoritative; server stores client-sent numbers only.
- Real U2Net (stub OK; on-demand later). - Real U2Net: stub OK; on-demand later. The one-photo server path stays in architecture.
- Woo create/publish and live taxonomy sync (Phase 1). Species offered in UI, pricing seeds, and Call 1 are **exactly** Woo-synced species-category leaves (CONTENT-WOO §2.2 / AGENTS §6 / DATA-MODEL `woo_categories`). No mock, seed, hardcoded, or fallback species list in this phase or later. - Woo create/publish and live taxonomy sync: Phase 1. Species offered in UI, pricing seeds, and Call 1 are **exactly** Woo-synced species-category leaves (CONTENT-WOO §2.2 / AGENTS §6 / DATA-MODEL `woo_categories`).
- Inference Call 1/2, LoRA. - Inference Call 1/2, LoRA: Phase 5.
- Offline PWA, IndexedDB sync, OCR, ruler. - Offline PWA, IndexedDB sync, OCR, ruler: Phase 2 (deferred stub).
- Fake upscale / inventing pixels. - Fake upscale / inventing pixels: undersized source warns and requires retake.
Deliverables: Deliverables:
@@ -140,11 +139,11 @@ Exit gate: Ty drives the API with curl through a full calibrated → ready cycle
## Phase 2 — Deferred: offline PWA / OCR / ruler (stub only) ## Phase 2 — Deferred: offline PWA / OCR / ruler (stub only)
**Deferred post-POC.** Do not implement for the online-only MVP. **Deferred post-POC.** The online-only MVP does not implement offline capture.
Capture UX for POC lives in early Phase 1 / Gate C (online hybrid). See AGENTS.md §2. Capture UX for POC lives in early Phase 1 / Gate C (online hybrid). See AGENTS.md §2.
Out of scope until a later product decision reopens offline: Offline PWA, OCR, and ruler detection are deferred to a later product decision:
- Workbox service worker, IndexedDB draft sync, airplane-mode capture - Workbox service worker, IndexedDB draft sync, airplane-mode capture
- Tesseract.js OCR for SKU - Tesseract.js OCR for SKU
@@ -321,7 +320,7 @@ Exit gate: Ty signs off on UAT results; v1 declared done.
| Host port/Caddy collision with co-resident apps (e.g. bolt.diy) | deploy conflict | Phase 0/6 inventory worksheet before any port bind | | Host port/Caddy collision with co-resident apps (e.g. bolt.diy) | deploy conflict | Phase 0/6 inventory worksheet before any port bind |
Ruler detection is **deferred** with offline/OCR (Phase 2 stub). Manual length is Ruler detection is **deferred** with offline/OCR (Phase 2 stub). Manual length is
authoritative for POC. Do not treat ruler confidence as a POC risk row. authoritative for POC. Ruler confidence is not a POC risk row.
--- ---
@@ -332,4 +331,4 @@ authoritative for POC. Do not treat ruler confidence as a POC risk row.
- `pytest` + integration + UAT green; inference-off path green. - `pytest` + integration + UAT green; inference-off path green.
- Deployed on the inventoried host (`APP_HOSTNAME` from `deploy/INVENTORY.md`), HTTPS, backed up, restore tested, runbook + key-rotation verified. - Deployed on the inventoried host (`APP_HOSTNAME` from `deploy/INVENTORY.md`), HTTPS, backed up, restore tested, runbook + key-rotation verified.
- Repo on gitea-atd (`Ty_Tech/SlabUploader`) is source of truth; docs current. - Repo on gitea-atd (`Ty_Tech/SlabUploader`) is source of truth; docs current.
- Do not treat `docs/archive/PRD-2026-08.txt` as implementation SoT. - `docs/archive/PRD-2026-08.txt` is frozen history only; live docs are the implementation SoT.
+1 -1
View File
@@ -162,7 +162,7 @@ Sheet/slider prefs are client localStorage only in POC (not in SettingsView).
- `DELETE /api/v1/slabs/{id}` → `204`. Soft: only unpublished drafts. Published slabs cannot be deleted from the app. - `DELETE /api/v1/slabs/{id}` → `204`. Soft: only unpublished drafts. Published slabs cannot be deleted from the app.
### Photo operations ### Photo operations
- `POST /api/v1/slabs/{id}/u2net/{pid}` — **post-POC.** "Try harder." Server runs U2Net on this one photo, returns a better mask. Do not implement or expose in Gate C / first listing. Keep the contract; do not delete. - `POST /api/v1/slabs/{id}/u2net/{pid}` — **post-POC.** "Try harder." Server runs U2Net on this one photo, returns a better mask. The contract is preserved but not implemented or exposed in Gate C / first listing.
- Returns `202` `{ mask_url: "..." }`. Client uses the mask to re-compute area/widths locally. - Returns `202` `{ mask_url: "..." }`. Client uses the mask to re-compute area/widths locally.
- `404` if photo not found. - `404` if photo not found.
- `GET /api/v1/slabs/{id}/photos/{pid}/original` → `image/*` (original, while retained). - `GET /api/v1/slabs/{id}/photos/{pid}/original` → `image/*` (original, while retained).
+3 -3
View File
@@ -100,7 +100,7 @@ Return valid JSON matching this schema:
- **Confidence gate (default threshold 0.7):** - **Confidence gate (default threshold 0.7):**
- Field confidence **≥ threshold** → pre-populate that field (mutable; - Field confidence **≥ threshold** → pre-populate that field (mutable;
user may clear or change it). user may clear or change it).
- Field confidence **< threshold** → leave empty. Do not show the model's - Field confidence **< threshold** → leave empty. The model's
low-confidence guess as a default. low-confidence guess as a default.
- Call 1 does not define the ready gate. Species + figure (or any vision - Call 1 does not define the ready gate. Species + figure (or any vision
subset) is assist/prefill only. Ready is the **full named set** in AGENTS §7 subset) is assist/prefill only. Ready is the **full named set** in AGENTS §7
@@ -135,7 +135,7 @@ injected by deterministic templates.
``` ```
You are a professional product copywriter for premium, one-of-a-one wood You are a professional product copywriter for premium, one-of-a-one wood
slabs. Write compelling, natural-sounding descriptions. Use the brand voice slabs. Write compelling, natural-sounding descriptions. Use the brand voice
provided. Do not invent measurements — use only the provided data. provided. Measurements are not invented; only the provided data is used.
``` ```
### User prompt (assembled at runtime) ### User prompt (assembled at runtime)
@@ -160,7 +160,7 @@ Write:
2. A paragraph describing the character, grain, color, and use cases 2. A paragraph describing the character, grain, color, and use cases
3. A call to action 3. A call to action
Keep the tone appropriate for a premium lumber buyer. Do not repeat the Keep the tone appropriate for a premium lumber buyer. The
dimensions — those are handled by the template. Focus on the beauty and dimensions — those are handled by the template. Focus on the beauty and
versatility of the slab. versatility of the slab.
+11 -12
View File
@@ -12,7 +12,7 @@ Inference, Woo payload, API, and schema live in other docs.
1. **Determinism** — same inputs → bit-identical outputs. No randomness, no timestamps in math, no network calls for the math. 1. **Determinism** — same inputs → bit-identical outputs. No randomness, no timestamps in math, no network calls for the math.
2. **Manual entry is authoritative** — user-entered length, thickness, SKU, and price always win over any computed value. 2. **Manual entry is authoritative** — user-entered length, thickness, SKU, and price always win over any computed value.
3. **Fallback chain is explicit** — every computed value has a defined fallback; the system never silently guesses. 3. **Fallback chain is explicit** — every computed value has a defined fallback; the system never silently guesses.
- BG removal: chroma-key / threshold → four knobs (sheet, sensitivity, edge offset, feather) live on capture → retake. U2Net last-resort is deferred from POC (do not delete from architecture). - BG removal: chroma-key / threshold → four knobs (sheet, sensitivity, edge offset, feather) live on capture → retake. U2Net last-resort is deferred from POC; the contract stays in the architecture.
- Length axis: min-area bounding rect → user rotate/confirm → retake if the photo is unusable. - Length axis: min-area bounding rect → user rotate/confirm → retake if the photo is unusable.
- Area: requires a single contiguous slab mask; broken mask → flag and retake. - Area: requires a single contiguous slab mask; broken mask → flag and retake.
4. **Units** — inches in 1/8" steps; sqft and bdft to 2 decimals; price half-up to 2 decimals. Those rounded values are what get stored. No sqin in the UI, tests, or product copy. 4. **Units** — inches in 1/8" steps; sqft and bdft to 2 decimals; price half-up to 2 decimals. Those rounded values are what get stored. No sqin in the UI, tests, or product copy.
@@ -33,8 +33,7 @@ update / switch link. No polyfill strategy in POC.
Load-bearing client APIs for the deterministic path include canvas (or OffscreenCanvas where used) Load-bearing client APIs for the deterministic path include canvas (or OffscreenCanvas where used)
for mask overlay and knob re-run, image decode/crop/encode for 3:4 transparent PNG prep, and for mask overlay and knob re-run, image decode/crop/encode for 3:4 transparent PNG prep, and
standard fetch to the app API. Do not depend on APIs outside this inventory without updating this standard fetch to the app API. Only APIs listed here are used; update this section before adding new ones.
section.
## 2. Units and rounding ## 2. Units and rounding
@@ -91,9 +90,9 @@ round trip for mask tuning in POC.
- **Black:** grayscale threshold. Same flood-fill (protects dark grain). - **Black:** grayscale threshold. Same flood-fill (protects dark grain).
- **POC path:** client-side only (sheet detect + four knobs). If the edge is still - **POC path:** client-side only (sheet detect + four knobs). If the edge is still
wrong after tuning, **retake**. wrong after tuning, **retake**.
- **Post-POC fallback (deferred, not deleted):** U2Net matting on one photo via - **Post-POC fallback (deferred, contract preserved):** U2Net matting on one photo via
FastAPI. Mask returns; knobs still apply on the client. Do not ship the control FastAPI. Mask returns; knobs still apply on the client. The U2Net control is not
in Gate C / first listing. Do not remove the contract from architecture. shipped in Gate C / first listing. The contract stays in the architecture for post-POC.
- Morphological close, then feather per the setting. - Morphological close, then feather per the setting.
### 3.5 Edge quality ### 3.5 Edge quality
@@ -153,7 +152,7 @@ Applies to every inventory photo of the slab (first photo and the rest).
configurable in settings). configurable in settings).
- Transparent **PNG only**. - Transparent **PNG only**.
- Slab centered. **80% fill at the extremes** (widest and tallest points of the slab). Extra margin where the slab is narrower. - Slab centered. **80% fill at the extremes** (widest and tallest points of the slab). Extra margin where the slab is narrower.
- After crop, if the source has enough pixels, shorter side ≥ **1600 px**. If it cannot, warn and ask for a retake — do not invent pixels. - After crop, if the source has enough pixels, shorter side ≥ **1600 px**. If it cannot, warn and ask for a retake. The source must supply enough pixels.
- Original + processed kept while draft/retry; both purged after successful publish (server storage; see Data Model). - Original + processed kept while draft/retry; both purged after successful publish (server storage; see Data Model).
## 6. Pricing ## 6. Pricing
@@ -187,7 +186,7 @@ GREEN_SAT_MIN = 40
GREEN_VAL_MIN = 40 GREEN_VAL_MIN = 40
BLACK_THRESH = 30 BLACK_THRESH = 30
``` ```
Sensitivity, edge offset, and feather map onto these at runtime. Users do not edit the raw HSV numbers. Sensitivity, edge offset, and feather map onto these at runtime. Users interact with the knobs, not the raw HSV numbers.
## 8. Test vectors ## 8. Test vectors
@@ -213,7 +212,7 @@ One square end, one 45° cut. Length axis follows prevailing length, not the dia
Slab centered in a 3:4 frame. At the widest and tallest points, fill = 0.80. PNG with alpha. Shorter side ≥ 1600 when the source allows. Slab centered in a 3:4 frame. At the widest and tallest points, fill = 0.80. PNG with alpha. Shorter side ≥ 1600 when the source allows.
### TV-7 Too-small source ### TV-7 Too-small source
After 80% crop, shorter side would be below 1600 and the source cannot supply it. Warn. Do not upscale from nothing. That photo is not publishable until retake. After 80% crop, shorter side would be below 1600 and the source cannot supply it. Warn; no upscaling from nothing. That photo is not publishable until retake.
### TV-8 Pricing ### TV-8 Pricing
bdft 0.96, species $12.50/bdft → rec **12.00**. bdft 0.96, species $12.50/bdft → rec **12.00**.
@@ -240,9 +239,9 @@ Price 12.345 → **12.35**.
7. 3:4 portrait is the PIP crop, configurable in settings. 7. 3:4 portrait is the PIP crop, configurable in settings.
8. Client does all of this math. Server stores the numbers the client sends. 8. Client does all of this math. Server stores the numbers the client sends.
## 10. Out of scope here (covered in other docs) ## 10. Cross-reference to other docs
| Topic | Doc | | Topic | Depth doc(s) |
|---|---| |---|---|
| Call 1 / Call 2 prompts, taxonomy mapping | PROMPTS, CONTENT-WOO | | Call 1 / Call 2 prompts, taxonomy mapping | PROMPTS, CONTENT-WOO |
| Portable Call 1→Call 2 context (full resend default) | ARCHITECTURE §9, PROMPTS | | Portable Call 1→Call 2 context (full resend default) | ARCHITECTURE §9, PROMPTS |
@@ -251,4 +250,4 @@ Price 12.345 → **12.35**.
| HTTP contract, taxonomy `taxonomy_anchor` | OPENAPI | | HTTP contract, taxonomy `taxonomy_anchor` | OPENAPI |
| Client vs server topology, validation module | ARCHITECTURE | | Client vs server topology, validation module | ARCHITECTURE |
| Auto-dimension overlay, figure-weighted price | IMPL-PLAN (v1.5) | | Auto-dimension overlay, figure-weighted price | IMPL-PLAN (v1.5) |
| Offline capture | non-goal (online-only POC; see AGENTS) | | Online-only capture (offline deferred) | AGENTS §2, ARCHITECTURE §4 |
+8 -8
View File
@@ -7,14 +7,14 @@ Follow the sections in order. Each one names what you do, what you should see, a
lives. lives.
**Inference is OFF for this walk.** The optional ON path is only valid after Gate C is green and **Inference is OFF for this walk.** The optional ON path is only valid after Gate C is green and
the inference endpoint is already configured. Do not turn it on here. the inference endpoint is already configured. Inference stays off here.
--- ---
## 1. Host and deploy preconditions ## 1. Host and deploy preconditions
Before this walk, the app must already be on the inventoried host. This section only checks that. Before this walk, the app must already be on the inventoried host. This section only checks that.
Do not invent host IPs or hostnames. Read them from `deploy/INVENTORY.md`. Host IPs and hostnames come from `deploy/INVENTORY.md`.
1. **Inventory is filled.** `deploy/INVENTORY.md` has `APP_HOST`, `APP_HOSTNAME`, ports, Caddy 1. **Inventory is filled.** `deploy/INVENTORY.md` has `APP_HOST`, `APP_HOSTNAME`, ports, Caddy
location, and the smoke results. It is the only source for what runs where on this host. location, and the smoke results. It is the only source for what runs where on this host.
@@ -41,7 +41,7 @@ Settings.
1. **Store is on HTTPS.** WordPress only offers Application Passwords over HTTPS. The store must 1. **Store is on HTTPS.** WordPress only offers Application Passwords over HTTPS. The store must
already be on TLS. If it is not, stop and fix the store first. already be on TLS. If it is not, stop and fix the store first.
2. **Dedicated low-privilege user.** Create or use a WordPress user that can create and edit 2. **Dedicated low-privilege user.** Create or use a WordPress user that can create and edit
products and upload media. Do not reuse the store admin login. A shop manager role or a custom products and upload media. The store admin login is not reused. A shop manager role or a custom
role with product create/edit plus media upload is enough. role with product create/edit plus media upload is enough.
3. **Generate the password.** Sign in as that user. Go to **Users → Profile → Application 3. **Generate the password.** Sign in as that user. Go to **Users → Profile → Application
Passwords**. Generate a password and label it "SlabUploader". Copy the password. WordPress Passwords**. Generate a password and label it "SlabUploader". Copy the password. WordPress
@@ -61,7 +61,7 @@ the old password in the WP profile and entering a new one in Settings, then re-r
## 3. Practice build rules ## 3. Practice build rules
These rules keep practice runs invisible to customers. They are locked. Do not change them for These rules keep practice runs invisible to customers. They are locked. Changes are not made for
the walk. the walk.
- **SKU prefix `SLAB-UAT-*`.** Every practice listing uses a SKU that starts with `SLAB-UAT-`. - **SKU prefix `SLAB-UAT-*`.** Every practice listing uses a SKU that starts with `SLAB-UAT-`.
@@ -69,12 +69,12 @@ the walk.
- **Always a Woo draft.** A `SLAB-UAT-*` SKU creates a WooCommerce draft even if Settings say - **Always a Woo draft.** A `SLAB-UAT-*` SKU creates a WooCommerce draft even if Settings say
publish. Customers cannot open it. This is hard rule in `AGENTS.md` §5. publish. Customers cannot open it. This is hard rule in `AGENTS.md` §5.
- **`woo_create_status` defaults to draft.** The Settings field that controls create status - **`woo_create_status` defaults to draft.** The Settings field that controls create status
defaults to `draft`. For practice you do not need to change it. If it is `publish`, the defaults to `draft`. Practice uses the default. If it is `publish`, the
`SLAB-UAT-*` rule still forces a draft. `SLAB-UAT-*` rule still forces a draft.
- **Customers never see practice listings.** A Woo draft is hidden from the storefront. If you - **Customers never see practice listings.** A Woo draft is hidden from the storefront. If you
can see the product on the live store, something is wrong. can see the product on the live store, something is wrong.
If a practice SKU is not `SLAB-UAT-*`, it is not a practice run. Do not publish a real SKU in If a practice SKU is not `SLAB-UAT-*`, it is not a practice run. Real SKUs are not published in
this walk. this walk.
--- ---
@@ -114,7 +114,7 @@ hard stop. Switch to a supported browser.
1. You are on the review screen. Fill every required field. Inference is OFF, so everything starts 1. You are on the review screen. Fill every required field. Inference is OFF, so everything starts
empty. empty.
2. **Species.** Pick exactly one from the synced store list. The list came from `test-woo`. 2. **Species.** Pick exactly one from the synced store list. The list came from `test-woo`.
Do not type a species that is not in the list. Only species in the list may be typed.
3. **Wood categories.** Pick at least one from the synced list. 3. **Wood categories.** Pick at least one from the synced list.
4. **Edge type, figure, grade.** Pick from the synced lists. At least one figure, at least one 4. **Edge type, figure, grade.** Pick from the synced lists. At least one figure, at least one
grade. grade.
@@ -207,7 +207,7 @@ After the walk, decide what to do with the Woo draft UAT product.
**Real live publish is a separate step.** It is not part of this walk. A real product uses a **Real live publish is a separate step.** It is not part of this walk. A real product uses a
non-UAT SKU (no `SLAB-UAT-` prefix) and is published only after you review it. That is a non-UAT SKU (no `SLAB-UAT-` prefix) and is published only after you review it. That is a
different decision. Do not run it here. The name of that step is **final POC publish**, and it different decision. That step is not run here. The name of that step is **final POC publish**, and it
is gated on your review of one real listing. is gated on your review of one real listing.
--- ---
+9 -14
View File
@@ -46,7 +46,7 @@ There are no calibration photos in this design. Only inventory photos exist.
### Mask overlay and four knobs ### Mask overlay and four knobs
The app removes the background sheet and draws the mask as an overlay on the source photo, showing The app removes the background sheet and draws the mask as an overlay on the source photo, showing
which pixels count as slab and which do not. The owner looks at that edge against the real wood. which pixels count as slab and which do not. The owner reviews that edge against the real wood.
This is the only quality check in the pipeline. There is no confidence score, no auto-gate, and no This is the only quality check in the pipeline. There is no confidence score, no auto-gate, and no
photo-quality checker. A clipped or over-inclusive mask shifts every downstream number with nothing photo-quality checker. A clipped or over-inclusive mask shifts every downstream number with nothing
later to catch it, so the eye on the overlay is what stands behind the measurement. later to catch it, so the eye on the overlay is what stands behind the measurement.
@@ -208,26 +208,21 @@ Exact minimum version pins are still tracked under issue #4. The matrix above is
for which classes of client are in scope. for which classes of client are in scope.
Unsupported browser behavior: hard stop. Show a clear message that this browser is not supported, Unsupported browser behavior: hard stop. Show a clear message that this browser is not supported,
with a link to update or switch to a supported browser. Do not attempt a broken mask. No polyfill with a link to update or switch to a supported browser. No polyfill
strategy in this version. strategy in this version.
Load-bearing client surfaces (do not silently drop): canvas-based mask overlay and live knob re-run, Load-bearing client surfaces that must remain: canvas-based mask overlay and live knob re-run,
image crop/prep to 3:4 transparent PNG, file/photo intake for inventory shots, and the online API image crop/prep to 3:4 transparent PNG, file/photo intake for inventory shots, and the online API
calls for draft upload, review, and publish. Depth for APIs stays in `docs/TECH-SPEC-PIPELINE.md` calls for draft upload, review, and publish. Depth for APIs stays in `docs/TECH-SPEC-PIPELINE.md`
and `docs/OPENAPI.md`. and `docs/OPENAPI.md`.
## What this version does not show ## Deferred features
These are locked out for now; they do not appear on any screen: Photo quality, OCR, ruler detection, server-side measuring, U2Net control, and offline capture are
deferred post-POC. The overlay edge plus the owner's eye is the only quality gate. SKU is typed by
- No photo-quality checker and no banner over the photo telling the owner it is bad. The overlay edge hand. Length is entered by hand; the browser derives its own pixel-to-inch scale. The browser owns
plus the owner's eye is the only gate. the happy path for measuring and cropping. The U2Net one-photo contract stays in the architecture
- No OCR of a printed SKU label. SKU is typed by hand. for later. Capture is online only.
- No ruler or scale detection. Length is entered by hand; the browser derives its own pixel-to-inch
scale from that length and the confirmed axis.
- No server-side measuring or cropping as the source of truth. The browser owns the happy path.
- No U2Net "try harder" control in this version. It stays in the architecture for later.
- No offline capture, no airplane-mode flow. Online only.
## Where each job lives ## Where each job lives