docs(phase2): reconcile requirements and migrate capabilities/contracts
Surface-matrix sweep of every source doc; added nine missed behaviors (METADATA-115, REVIEW-50, APP-55/60/65, SETTINGS-45 mode, Generate-text availability, defaults-off). 153 requirements, 0 coverage gaps. Migrated capabilities to docs/capabilities/ and contracts to docs/contracts/; added WOO-API, API, DATA-MODEL, PROMPTS, UX, TEST-SPEC. Populated MILESTONES; branch-neutral trunk docs; renamed umbrella term to Woo Slab Taxonomy. Archived reconciliation working records under .audit/archive/.
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
# Milestone 1 — Capture
|
||||
|
||||
Runs in the browser on phone and PC as ordinary client code.
|
||||
No inference URL. No model. No backend. Mask, rectangle, measurements, crop, and PNG encode are deterministic functions of the photo and user inputs.
|
||||
|
||||
Milestone 1 uses one reference photo; Milestone 2 adds the batch. Milestone 1 ends when the user sees the inventory PNG and measurements. Milestone 2 is Photos (`docs/capabilities/PHOTOS.md`); Milestone 3 is Create (`docs/capabilities/CREATE.md`). This file does not create a WooCommerce product.
|
||||
|
||||
## Requirements impact
|
||||
|
||||
| Requirement | Impact |
|
||||
|---|---|
|
||||
| CAPTURE-5, CAPTURE-135, CAPTURE-140 | deterministic client core; server stores, never recomputes |
|
||||
| CAPTURE-10 | supported clients and hard stop |
|
||||
| CAPTURE-20, CAPTURE-35 | sheet setup and detection |
|
||||
| CAPTURE-40, CAPTURE-41, CAPTURE-45, CAPTURE-50, CAPTURE-55 | mask controls, sensitivity, live re-run, overlay, retake |
|
||||
| CAPTURE-60, CAPTURE-65 | length axis |
|
||||
| CAPTURE-70, CAPTURE-75, CAPTURE-80, CAPTURE-85, CAPTURE-90 | inputs and measure math |
|
||||
| CAPTURE-95, CAPTURE-100, CAPTURE-105 | inventory PNG |
|
||||
| CAPTURE-141, CAPTURE-145, CAPTURE-150, CAPTURE-155, CAPTURE-160 | preview, knobs, failure, rounding |
|
||||
| APP-10 | device draft and resume |
|
||||
| QUALITY-40, QUALITY-45, QUALITY-55, QUALITY-60, QUALITY-65, QUALITY-70, QUALITY-75, QUALITY-80, QUALITY-85, QUALITY-100 | deterministic tests and vectors |
|
||||
|
||||
## Setup
|
||||
|
||||
Photograph the slab on a green or black sheet.
|
||||
|
||||
- Sheet fills the frame around the slab.
|
||||
- Slab is fully on the sheet.
|
||||
- First photo is top-down, lens parallel to the face.
|
||||
|
||||
The app expects that sheet. Background removal keys green or black. Other backgrounds are out of Milestone 1.
|
||||
|
||||
## Use case
|
||||
|
||||
If a device draft exists:
|
||||
|
||||
- App opens Resume.
|
||||
- User chooses Continue or Start fresh.
|
||||
- Continue: app restores the last approved state.
|
||||
- Start fresh: app discards the draft and opens Add photo.
|
||||
|
||||
Otherwise the app opens Add photo.
|
||||
|
||||
1. User adds one photo taken under Setup.
|
||||
2. App decodes the photo and opens Mask. App keys green or black and shows an overlay: slab stays the photograph; removed pixels are a light gray checkerboard.
|
||||
3. User sets sheet Auto / Green / Black and sensitivity 0–100 (slider or minus / plus). App updates the control immediately. App recomputes the overlay 2.0 seconds after the last sensitivity change. User adjusts until only the slab remains, then approves. App blocks approve if the mask has no slab pixels; user retakes. The approved mask is the footprint for every later step.
|
||||
4. App draws the minimum-area bounding rectangle of the mask and the length axis on the long side of that rectangle. User rotates the axis if it does not follow the slab length, then approves the axis.
|
||||
5. User enters length `L` in inches (1/8 in steps) and thickness (1/8 in steps), then presses Calculate.
|
||||
6. App sets `scale = longest_axis_px / L` (mask/wood span along the approved direction ÷ user `L`; rectangle is direction only).
|
||||
7. App computes widths, sqft, and bdft from the mask. App crops the masked slab into a 3:4 portrait frame: slab centered, 90% fill at the widest and tallest points, background transparent. App writes that frame as an inventory PNG (`image/png`, 8-bit RGBA).
|
||||
8. User sees the transparent PNG and the numbers. Milestone 1 stops here.
|
||||
|
||||
Calculate does not create a WooCommerce product.
|
||||
|
||||
## Browsers
|
||||
|
||||
Phone: iOS Safari, Android Chrome.
|
||||
PC: Chrome, Edge, Firefox.
|
||||
Other clients get a hard stop.
|
||||
|
||||
## States
|
||||
|
||||
One photo component is reused. Each state advances on approve. Back returns to the previous state. A device draft restores the last approved state.
|
||||
|
||||
1. Resume — only when a device draft exists. Continue or Start fresh.
|
||||
2. Add photo — camera or picker. One photo. Setup rules visible.
|
||||
3. Mask — background removal on that photo.
|
||||
4. Length axis — bounding rectangle and long-side axis on the same photo.
|
||||
5. Measure — length, thickness, Calculate, crop, inventory PNG, widths, sqft, bdft. Milestone 1 stops here.
|
||||
|
||||
## Display
|
||||
|
||||
Preview fits the device width. Height is capped so Mask and Measure controls stay on screen. Phone and PC use the same states.
|
||||
|
||||
The preview is display only. Mask, rectangle, crop, `scale`, sqft, and PNG encode use the source photo pixels, not the CSS size of the preview.
|
||||
|
||||
## Runtime
|
||||
|
||||
Browser APIs: `createImageBitmap`, `canvas` / `OffscreenCanvas`, Web Worker, `convertToBlob({ type: "image/png" })`, IndexedDB.
|
||||
`idb-keyval` may wrap IndexedDB.
|
||||
No OpenCV, ONNX, U2Net, or image-editor kit.
|
||||
Sensitivity 0–100 maps to green chroma tightness and black brightness cutoff in the worker.
|
||||
|
||||
## Mask
|
||||
|
||||
Overlay: slab remains the photograph. Removed pixels are a light gray checkerboard.
|
||||
|
||||
Controls on this state, with the photo visible:
|
||||
|
||||
- Sheet: Auto, Green, or Black
|
||||
- Sensitivity: 0–100, step 1. Slider with minus and plus on each side. Button hit targets sized for a thumb.
|
||||
|
||||
The control value updates immediately. The overlay recomputes 2.0 seconds after the last sensitivity change. A sheet change may recompute on the change.
|
||||
|
||||
Mask work runs in the worker. The last good overlay stays visible while a pass runs. Show a busy mark only if a pass lasts more than a fraction of a second. If a pass fails, keep the last overlay; the user may retake.
|
||||
|
||||
Approve is blocked when the mask has no slab pixels. User retakes.
|
||||
|
||||
User approves the mask when only the slab remains. That mask is the footprint for Length axis, crop, measurements, and the inventory PNG.
|
||||
|
||||
## Length axis
|
||||
|
||||
On the same photo, keep the approved mask in view and draw the minimum-area bounding rectangle of the mask with the length axis on the long side of that rectangle. User rotates the rectangle (slider with minus and plus) until that direction follows the slab length, then approves the axis.
|
||||
|
||||
## Measure
|
||||
|
||||
User enters length `L` in inches (1/8 in steps) and thickness (1/8 in steps), then presses Calculate.
|
||||
|
||||
- `scale = longest_axis_px / L` where `longest_axis_px` is the mask/wood span along the approved length direction (slab pixels end-to-end on that axis), not the rectangle edge length. The rectangle sets direction only; user-entered `L` is wood end→end along that direction.
|
||||
- Widths: min, max, avg from samples taken every 6 in along the approved length axis, perpendicular to it, after dropping the first and last 6 in of the span (bulk widths, not tips). If `L ≤ 12 in` there are no interior stations and all three are 0.
|
||||
- `sqft = (mask_pixels / scale²) / 144` (2 decimals)
|
||||
- `bdft = sqft × thickness_in` (2 decimals)
|
||||
- Crop: 3:4 portrait, slab centered, 90% fill at the widest and tallest points, transparent background
|
||||
- File: inventory PNG, `image/png`, 8-bit RGBA, alpha kept
|
||||
|
||||
User sees the transparent PNG and those numbers. Stop. Calculate does not create a WooCommerce product.
|
||||
|
||||
## Crop
|
||||
|
||||
On Calculate, the app builds the inventory image from the approved mask:
|
||||
|
||||
1. Keep slab pixels from the source photo. Removed pixels are transparent.
|
||||
2. Place the slab in a 3:4 portrait frame, centered.
|
||||
3. Scale so the widest and tallest points of the slab fill 90% of the frame. Extra margin where the slab is narrower.
|
||||
4. After that crop, shorter side ≥ 800px when the source can supply it. Otherwise warn and require a new photo. No upscale from an undersized source.
|
||||
5. Encode as PNG with alpha.
|
||||
|
||||
## Device draft
|
||||
|
||||
One in-progress slab is stored on the device. This is not a WooCommerce draft.
|
||||
|
||||
On open or refresh, if that draft exists, the app opens in Resume.
|
||||
|
||||
- Continue restores the last approved state, including Measure.
|
||||
- Start fresh discards the device draft and opens Add photo.
|
||||
|
||||
Milestone 3 clears the device draft after Woo create.
|
||||
|
||||
## Inventory PNG
|
||||
|
||||
The calibration photo is the measurement reference (`CAPTURE-25`, `CAPTURE-115`). Filename is an implementation detail.
|
||||
|
||||
| Property | Value |
|
||||
|---|---|
|
||||
| Format | PNG, 8-bit RGBA (`image/png`) |
|
||||
| Alpha | Kept through encode and upload |
|
||||
| Aspect | 3:4 portrait |
|
||||
| Layout | Slab centered, 90% fill at the widest and tallest points |
|
||||
| Size | After crop, shorter side ≥ 800px when the source can supply it |
|
||||
|
||||
Source below that floor: warn and require a new photo. No upscale from an undersized source.
|
||||
@@ -0,0 +1,118 @@
|
||||
# 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, context, dimension safety, logging |
|
||||
| METADATA-70, METADATA-75, METADATA-80, METADATA-85, METADATA-90, METADATA-95 | template fallback, non-blocking, prompt selection, fact block |
|
||||
| METADATA-100, METADATA-105, METADATA-110, METADATA-115 | feat mapping, prompt storage, 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; 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, short_description, and description are required and satisfy typed,
|
||||
generated, or templated text (`REVIEW-10`); 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 name, short_description, and description
|
||||
(`METADATA-55`). It is a fresh request carrying the full Call 1 context and the literal dimension
|
||||
fact block; 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, deterministic templates produce the prose so create never lacks it
|
||||
(`METADATA-70`); the fallback title uses the primary figure term with a hyphen separator
|
||||
(`METADATA-80`). Prompts live in the database with all revisions (`METADATA-105`). 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`).
|
||||
|
||||
## 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`), and cross-browser end-to-end verification (`QUALITY-115`). The V1 instrumentation work
|
||||
is out of M3.
|
||||
@@ -0,0 +1,88 @@
|
||||
# Milestone 2 — Photos
|
||||
|
||||
Builds on Milestone 1. Spec for calibration math and inventory PNG properties: `docs/capabilities/CAPTURE.md`.
|
||||
This milestone gets every photo of one slab background-removed and cropped store-ready.
|
||||
It does not fill Complete-listing taxonomy, SKU, price, or copy. It does not create a WooCommerce product.
|
||||
No inference URL. No model. Mask and crop for non-calibration shots reuse the approved calibration params as ordinary client code.
|
||||
|
||||
## Requirements impact
|
||||
|
||||
| Requirement | Impact |
|
||||
|---|---|
|
||||
| CAPTURE-25 | batch of one or more; owner picks the calibration photo |
|
||||
| CAPTURE-30 | calibration drives mask, axis, measure, crop; others reuse them |
|
||||
| CAPTURE-100, CAPTURE-105 | crop rules and size floor reused on other photos |
|
||||
| CAPTURE-110 | per-photo error; remaining photos proceed |
|
||||
| CAPTURE-115 | measures tied to the calibration photo; others are visual inventory |
|
||||
| CAPTURE-120, CAPTURE-125 | dimension overlay |
|
||||
| CAPTURE-130 | photos-ready lineup order |
|
||||
| APP-10 | device draft restores the batch and calibration choice |
|
||||
|
||||
## Goal
|
||||
|
||||
Phone capture of one slab → a lined-up set of Woo-compatible inventory PNGs, plus Milestone 1 calibration numbers on the reference shot, plus one annotated copy of the calibration PNG with dimension overlays.
|
||||
|
||||
## Use case
|
||||
|
||||
1. User adds a batch of one or more photos of the same slab (Setup rules from Milestone 1: green or black sheet, top-down reference expectations still apply to the calibration choice).
|
||||
2. User selects which photo in the batch is the calibration photo.
|
||||
3. App runs the Milestone 1 workflow on that calibration photo only: Mask → Length axis → Measure (length `L`, thickness, Calculate).
|
||||
4. After Calculate, the app applies the approved mask sheet and sensitivity, and the same crop rules (3:4 portrait, 90% fill, transparent PNG, shorter-side floor), to every other photo in the batch.
|
||||
5. App adds a second copy of the calibration inventory PNG with dimension overlays burned in (see Dimension overlay).
|
||||
6. User sees Photos ready: inventory PNGs lined up in this order — clean calibration PNG, then the dimension-overlay copy of the calibration PNG, then the other batch photos in capture order — plus the Milestone 1 calibration details (widths, sqft, bdft, scale) presented as in Measure.
|
||||
|
||||
A batch of one photo still works: that photo is the calibration photo; the end set is the clean PNG plus the dimension-overlay copy.
|
||||
|
||||
## States (additions over Milestone 1)
|
||||
|
||||
1. Batch — add one or more photos; continue when the batch has at least one.
|
||||
2. Pick calibration — user chooses which batch photo is the reference.
|
||||
3. Mask / Length axis / Measure — Milestone 1 states on the calibration photo only.
|
||||
4. Photos ready — lineup order: clean calibration PNG → dimension-overlay copy → other batch photos in capture order; plus Milestone 1 numbers.
|
||||
|
||||
Device draft restores the last approved state, including the batch and which photo was calibration when those exist.
|
||||
|
||||
## Apply to non-calibration photos
|
||||
|
||||
For each non-calibration photo:
|
||||
|
||||
- Reuse the approved Mask sheet (Auto / Green / Black) and sensitivity from the calibration photo. Do not re-open Mask controls for that photo in this milestone.
|
||||
- Run background removal with those params; compose inventory PNG with the same crop rules as Milestone 1 Calculate.
|
||||
- If a photo yields an empty mask or fails the PNG size floor, keep it out of the ready set and show a clear per-photo error; other photos still proceed.
|
||||
|
||||
Scale, widths, sqft, and bdft stay tied to the calibration photo and user `L` / thickness. Non-calibration photos are visual inventory only.
|
||||
|
||||
## Dimension overlay
|
||||
|
||||
A second copy of the **calibration** inventory PNG is added to the collection. Overlays are black, large enough to read on phone and storefront.
|
||||
|
||||
Orientation follows the **user-approved length axis** from Milestone 1 (not the upright edges of the photo).
|
||||
|
||||
- **Length:** dimension graphic beside the wood on the right in axis-space (outside the slab edge along the length direction).
|
||||
- **Widths:** stations every 12 in along the approved length axis, starting 6 in from the **bottom** of the slab span, continuing while the station is not within 6 in of the top (stations at 6, 18, 30, … in inches along the axis while ≤ `L − 6`). Each width is drawn across the wood perpendicular to the length axis, with arrow tips on the left and right slab edges and the measurement text on that line.
|
||||
- **Bottom:** after the calibration photo’s EXIF orientation is applied, the bottom edge of that oriented photo establishes which end of the slab is bottom for width stations. Length-axis direction still follows the user-approved Milestone 1 axis; EXIF only picks which end is bottom vs top along that span.
|
||||
|
||||
## Photos-ready order
|
||||
|
||||
1. Clean calibration inventory PNG
|
||||
2. Dimension-overlay copy of the calibration PNG
|
||||
3. Remaining batch inventory PNGs in capture order
|
||||
|
||||
The clean calibration PNG remains in the set. The annotated copy is extra.
|
||||
|
||||
## Acceptance
|
||||
|
||||
On a phone UAT build:
|
||||
|
||||
- User can capture 1–N photos, pick calibration, complete Milestone 1 on that shot, and see every successful batch photo as a 3:4 transparent inventory PNG lined up.
|
||||
- Calibration measures match Milestone 1 presentation.
|
||||
- Dimension-overlay copy of the calibration PNG is present with black length and width graphics oriented to the approved axis; width stations start 6 in from EXIF-established bottom.
|
||||
- Lineup order is clean calibration → dimension overlay → other batch photos in capture order.
|
||||
- No Woo create. No inference URL.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Complete-listing fields (SKU, species, category, edge, figure, grade, thickness band, moisture, `fig-*` / `feat-*`, title, short title, description, price)
|
||||
- WooCommerce create and submission-ready taxonomy (Milestone 3: `docs/capabilities/CREATE.md`)
|
||||
- Work beyond `docs/capabilities/CREATE.md` unless Ty expands M3 in chat
|
||||
- Changing Milestone 1 mask/axis/measure math except to reuse its outputs for batch apply and overlays
|
||||
Reference in New Issue
Block a user