Files
SlabUploader/docs/UAT-PRACTICE.md
T

12 KiB
Raw Blame History

UAT Practice Walk: one SLAB-UAT-* listing

Status: WALK · for Ty to run · SlabUploader

This is the walkable practice plan. It proves one listing end to end without touching a live product. Follow the sections in order. Each one names what you do, what you should see, and where the rule lives.

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. Inference stays off here.


Milestone 3 exit criteria and field rules live in docs/capabilities/CREATE.md. This walk is the human practice path for a SLAB-UAT-* listing. Prefer docs/capabilities/CREATE.md if anything conflicts.

1. Host and deploy preconditions

Before this walk, the app must already be on the inventoried host. This section only checks that. Host IPs and hostnames come from deploy/INVENTORY.md.

  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. See docs/DEPLOYMENT.md §1 for the worksheet rules.
  2. Reachable over LAN/Tailscale. Your phone reaches https://${APP_HOSTNAME} on the same network (LAN or Tailscale). No public exposure. Verify with a browser, not curl.
  3. HTTPS only. The URL is https://. The browser shows a valid certificate. If the phone warns, the Caddy TLS trust is not set up yet. That is a deploy problem, not a listing problem.
  4. Health passes. In a browser on the phone, open https://${APP_HOSTNAME}/api/health. You should see an ok response. This is the same check in docs/DEPLOYMENT.md §8 step 1.
  5. Store URL is set. WOO_BASE_URL is in the host .env and points at the store over https://. It is not something you type in the app. See docs/DEPLOYMENT.md §3 and §5.

If any of these fail, fix the deploy before continuing. This walk does not cover Gate B host work. It assumes the app is up and reachable.


2. WordPress Application Password setup

You do this once per store, in the store's WordPress admin. Do it before you open the app's Settings.

  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.
  2. Dedicated low-privilege user. Create or use a WordPress user that can create and edit 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.
  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 shows it once.
  4. Enter it in the app. Open the app's Settings on the phone. Enter the WordPress username and the application password. The server stores them encrypted. The browser does not keep them.
  5. Run test-woo. In Settings, tap the test. It should report ok. This also resyncs the store's species, categories, tags, and attributes into the app. If it fails, the username or password is wrong, or the store is unreachable.

Rules: this is a WordPress Application Password, not WooCommerce consumer keys (ck_/cs_). The app never calls the store from the browser. FastAPI is the only caller. Rotate by revoking the old password in the WP profile and entering a new one in Settings, then re-running test-woo. Full lock: AGENTS.md §4 and §5, docs/DEPLOYMENT.md §5.


3. Practice build rules

These rules keep practice runs invisible to customers. They are locked. Changes are not made for the walk.

  • SKU prefix SLAB-UAT-*. Every practice listing uses a SKU that starts with SLAB-UAT-. Pick a unique one each time, for example SLAB-UAT-001.
  • 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.
  • woo_create_status defaults to draft. The Settings field that controls create status defaults to draft. Practice uses the default. If it is publish, the SLAB-UAT-* rule still forces a draft.
  • 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.

If a practice SKU is not SLAB-UAT-*, it is not a practice run. Real SKUs are not published in this walk.


4. Prove one listing end to end

This is the main walk. Run it on a phone browser first, then repeat on a PC browser. Both are in the signed compatibility matrix (docs/UX.md, signed 2026-09-06).

Supported browsers: iOS Safari, Android Chrome on phones; desktop Chrome, Edge, Firefox on PC. Exact version pins are tracked under issue #4. If the browser is not supported, the app shows a hard stop. Switch to a supported browser.

4.1 Capture

  1. Open the app on the phone. Start a new slab.
  2. Take one or more photos of the slab (the batch); the first should be top-down, lens parallel to the broad face. A tilted shot makes the numbers wrong. Retake if it is tilted.
  3. Mask overlay and controls. The app draws a mask over the photo. You see which pixels are slab and which are not. Tune the controls: Sheet (auto/green/black) and Sensitivity (0–100). A Sheet change runs immediately; a Sensitivity change waits 2000 ms. Each recomputes in the browser. Look at the edge against the real wood. If it is still off, retake the photo.
  4. Confirm the mask. Tap confirm.
  5. Length axis. The app draws the bounding rectangle and the length axis. Confirm it follows the slab's long direction. Rotate if it is skewed. On a nearly square slab, you say which way is length.
  6. Enter numbers by hand. Length in 1/8" steps. Thickness as a 1/8" pick. SKU: type SLAB-UAT-001 (or your chosen practice SKU).
  7. Check the computed numbers. The browser shows square feet, board feet, and width samples. Board feet = square feet × thickness in inches. No divide-by-12. If the numbers look wrong, go back and fix the mask or the length.
  8. Continue. This uploads the originals, the processed PNGs, and the numbers to the server. The slab status becomes calibrated.

4.2 Review

  1. You are on the review screen. Fill every required field. Inference is OFF, so everything starts empty.
  2. Species. Pick exactly one from the synced store list. The list came from test-woo. Only species in the list may be typed.
  3. Wood categories. Pick at least one from the synced list.
  4. Edge type, figure, grade. Pick from the synced lists. One edge type, at least one figure, exactly one grade.
  5. Thickness band. Derived, not picked: the server bands the measured thickness up into the synced Woo band and Review shows it read-only. Verify the shown band is the one the captured thickness rounds up into (QUALITY-95).
  6. Moisture. Keep the default (kiln-dried) or change it.
  7. fig- tags.* Optional; pick any from the synced list.
  8. feat- tags.* Zero or more. Only pick existing feat-* tags.
  9. Price. A recommendation fills from the species $/bdft rule times board feet. You can override it. If there is no rule for the species, the price starts empty. Type it. Publish is still allowed with a manual price.
  10. Title and short description. These are built for you from the primary wood category's pattern and the measurements. You can edit either before publish (REVIEW-10, METADATA-80).
  11. Description. With Generate text OFF the server produces it (METADATA-70). When inference is on you can trigger Generate text to have the model write it (METADATA-55).

Every empty required field shows an inline nudge where it sits. The slab cannot reach ready until the full set is filled.

4.3 Publish

  1. Tap Publish.
  2. The server checks the SKU against the store. If SLAB-UAT-001 is new, it creates the product.
  3. What you should see: a success message on the screen. The local draft and its photos are gone from the app. The slab status in the app is published.
  4. What that does NOT mean: the product is not live in the store. It is a WooCommerce draft. The app's "published" means the store create succeeded and the local row was cleaned up.

4.4 Confirm in the store

  1. Open the store's WooCommerce admin.
  2. Find the product by SKU SLAB-UAT-001.
  3. It must be a draft. Status is draft, not published.
  4. Check the fields: SKU, price, category (species), tags (fig-, feat-), attributes (Edge Type, Figure, Grade, Thickness, Moisture), and images (the processed transparent PNGs).
  5. Open the live storefront. The product must not appear. A draft is invisible to customers.

4.5 Repeat on a PC browser

Repeat 4.1 through 4.4 on a desktop browser (Chrome, Edge, or Firefox). Use a different practice SKU, for example SLAB-UAT-002. The flow must work the same way. This is the signed PC-browser compatibility check.


5. Pass and fail checks

You can see all of these without reading code.

Check Where Pass looks like
Health endpoint Phone browser, https://${APP_HOSTNAME}/api/health ok response
test-woo ok App Settings ok; species list is populated
woo_create_status is draft App Settings shows draft (or publish, but SLAB-UAT-* forces draft anyway)
Slab reaches calibrated App, after capture status is calibrated
Slab reaches ready App, after review no empty required fields; inline nudges gone
Publish succeeds App, after Publish success message; local draft is gone
Woo product exists as draft Store admin, products SKU SLAB-UAT-*, status draft
SKU prefix correct Store admin starts with SLAB-UAT-
Store not live Live storefront URL product does not appear
Board feet identity App review screen, or a fixture bdft = sqft × thickness in inches; no divide-by-12
Images are processed PNGs Store admin, product images transparent PNGs, not the original JPEGs

Duplicate SKU recovery

If you publish the same SKU twice, the second time the app stops before creating a second product. Under the SKU field you see: "This SKU already exists in the store (any status)." Two paths: edit the SKU to a new value, or open the existing listing. The draft stays in the app. Nothing is lost. This is the expected behavior, not a bug. See docs/contracts/CONTENT-WOO.md §2.5.

What a fail looks like

  • No success message after Publish. The app shows a plain message that the listing could not be created. No status number, no stack trace. The server kept a log. You can retry from the same screen without re-photographing.
  • A value is no longer valid. If a category, attribute, or price was removed from the store between sync and publish, that field shows "This value is no longer valid. Pick from the current list." Re-pick and retry.
  • Store unreachable. A plain message says the store could not be reached. Check the network and retry.

6. Cleanup

After the walk, decide what to do with the Woo draft UAT product.

  • Leave it or delete it. Both are fine. It is a draft. Customers cannot see it. If you delete it, the store admin is the place to do it. The app does not delete store products.
  • Never customer-visible. If the product is visible on the live storefront, it is not a draft. That is a bug. Stop and report it.

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 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.


Where each rule lives

Rule Source
Practice SKU forces draft AGENTS.md §5
woo_create_status default draft AGENTS.md §5, docs/contracts/CONTENT-WOO.md
App Password setup, not consumer keys AGENTS.md §4, deploy/
Host inventory before deploy deploy/INVENTORY.md
Capture → review → publish flow docs/contracts/UX.md
Board feet identity docs/REQUIREMENTS.md (CAPTURE-90)
Duplicate SKU recovery docs/contracts/CONTENT-WOO.md, docs/contracts/UX.md
PC browser compatibility docs/contracts/UX.md
M3 scope and exit docs/MILESTONES.md, docs/REQUIREMENTS.md