Files
SlabUploader/docs/contracts/PROMPTS.md
T
Ty 7287a55707 fix(inference): #86 tighten Call 1 prompt and closed lists
Ship locked expert Call 1 seed: order cats before edge, species=best
confidence, mill-count edge rules, Wild for cookies/burl, multi figure,
feature_tag_ids only (no free-text bags, no grade). LISTS keys match the
seed; feat- prefix stripped for the model. Gate and review UI apply
feature_tag_ids. Seed auto-activates on deploy when still seed-authored.
2026-09-20 22:54:36 -07:00

8.6 KiB
Raw Blame History

Prompts contract

Status: SPEC · 2026-09-18. Owns prompt storage, prompt inputs, and the two inference calls.

Requirements impact

Requirement Impact on this design
METADATA-5, METADATA-10, METADATA-15, METADATA-30 taxonomy choices and cardinality
METADATA-35, METADATA-40, METADATA-45, METADATA-50 Call 1 inputs, constraints, pre-fill, precedence
METADATA-55, METADATA-60, METADATA-65, METADATA-70 Call 2 output, inputs, dimension safety, inference-off path
METADATA-75, METADATA-80, METADATA-85, METADATA-90, METADATA-95 non-blocking, deterministic copy, pattern selection, fact block, overlay exclusion
METADATA-105, METADATA-106, METADATA-107 prompt storage, revision interface, auth
METADATA-66 generation logging
SETTINGS-30 brand voice and geo context
REVIEW-40, REVIEW-50 editability and field limits

1. Storage and revisions

  • Prompts live in the database, not in text files, with all revisions retained. Storage shape is docs/contracts/DATA-MODEL.md §7 (METADATA-105).
  • Revisions are append-only. Editing saves a new revision and moves the active pointer; a revision is never updated or deleted. Reset to default and reset to revision are pointer moves.
  • Each call reads the active revision fresh, and the revision used is recorded on the call (METADATA-66).
  • The seed text in §6 is read once on first run and written as revision 0 for each call. It is the only prompt content that ships with the application.

2. Revision interface

REST, no UI (METADATA-106):

  1. POST /api/v1/prompts/{call}/revisions appends a revision and returns it.
  2. POST /api/v1/prompts/{call}/activate moves the active pointer to a revision.
  3. GET /api/v1/prompts/{call} returns the active prompt and the revision list.

The interface is reachable on the trusted network only until it is authenticated (METADATA-107).

3. Call 1 — vision classification

Cites METADATA-35, METADATA-40, METADATA-45, METADATA-50.

When. Runs automatically after a calibrated draft uploads only when inference_enabled is true; also on demand or retry. With inference off it is skipped and the fields are filled by hand.

Inputs.

  • The clean processed photos at 1024 px long edge or less.
  • Closed LISTS from the synced Woo cache only: species, wood_categories, edge_terms, figure_terms, feature_tags (each with id + display name). Grade, thickness, and moisture are not sent to Call 1.
  • User metadata: SKU, length, thickness.

Constraints.

  • The model may only choose values from the supplied LISTS; it never invents categories or terms.
  • Feature tags are returned as feature_tag_ids from the supplied list only. Display names omit a leading feat- prefix; Woo remains authoritative for the tag set. No free-text observation bags.
  • Grade is never suggested (owner judgment).
  • Decide wood categories before edge type. Cookies and burl cuts prefer Wild edge when that term exists in the list.

Result fields. species_id + species_confidence; wood_category_ids + wood_category_confidence; edge_type_term_id + edge_confidence; figure_term_ids + figure_confidence (multi allowed); feature_tag_ids + feature_tag_confidence. Edge is singular; figure and feature tags are multi.

Pre-fill. At or above the threshold (default 0.7) the field is pre-filled and remains editable; below it the field stays empty and is not shown as a low-confidence guess. Typed values always win. Call 1 is assist-only and never gates publish. A runtime failure is classified recoverable or unrecoverable for the owner.

4. Call 2 — content prose

When. User-triggered only, via the Generate text control; never automatic. The control appears only when content generation is enabled and the endpoint is reachable.

Inputs.

  • The clean processed photos.
  • The metadata confirmed or changed in review, including the primary and secondary wood categories and the parent-category path.
  • The literal dimension fact block, exact strings for species, figure term, length, thickness, average width, width min–max, and board feet; no length-by-width-by-thickness rectangle assumption.
  • Brand voice and geo context.

No provider thread id is used, and Call 1's raw prompt and result are not sent (METADATA-60).

Constraints.

  • The model writes prose only and never invents or alters a dimension; every number comes from the fact block (METADATA-65).
  • The dimension-overlay image is never sent (METADATA-95).

Output. The long description prose. The server assembles name and short_description (METADATA-55, METADATA-80). The primary wood category selects the specialized prompt (METADATA-85). The owner can edit the result (REVIEW-40).

5. Fallback and templates

  • With inference off, the server produces the long description so create never lacks prose (METADATA-70).
  • The deterministic title and short-description patterns live in docs/contracts/CONTENT-WOO.md (METADATA-80).
  • The primary wood category selects the specialized Call 2 prompt (METADATA-85).
  • All generated text stays within the field limits in docs/contracts/WOO-API.md §9 (REVIEW-50).

6. Seed prompt text

Read once on first run and written as revision 0 for each call (METADATA-105). Authored here with the rest of the prompt discussion; the seed is the only prompt content that ships with the application.

The seed is the starting point for tuning, not a final text. Both calls are revised ad hoc through the §2 interface when UAT surfaces a miss.

call1 seed. Shipped text in backend/inference.py (CALL1_SEED), mirrored here for review.

You are a wood identification expert for retail lumber slabs. Judge only from the photos and the LISTS below. Use list ids only — never invent a name or id.

Work in this order: (1) species, (2) wood categories, (3) edge type, (4) figure, (5) feature tags. Decide wood categories before edge type — edge rules depend on product form.

For each field, pick from its list and give a confidence 0–1 (1 = certain, 0 = no idea). Prefer null or [] over a weak guess.

Species — which tree species is this slab. Match grain, color, and figure to the species list. If more than one entry is plausible, return only the single highest-confidence match (one id). Null only when none are credible.

Wood categories — product form / how it will be sold (live edge, dimensional, cookies & burl slices, turning blanks, etc.). Choose every wood_categories id that clearly fits; often one, sometimes more. [] if none fit. Finish this field before edge type.

Edge type — the long-edge mill profile. One id from edge_terms, or null only if none fit. Meanings (match the closest list name): • Square / square edge — both long edges milled straight (2 milled long edges). • Live one side / Live Edge 1 side — one long edge milled, the other natural bark or waney (1 milled long edge). • Live both / Live edge 2 sides — neither long edge milled; both natural (0 milled long edges). • Wild edge — use when the three mill-count cases do not fit, including cookies and burl cuts/slices (no conventional slab long-edge pair). Prefer Wild for those forms rather than null.

Figure — visible figure in the wood (curl, quilt, spalt, plain, burl, …). Zero or more ids from figure_terms that clearly apply.

Feature tags — defects and character marks the store tags for shoppers (knots, checks, inclusions, …). Zero or more ids from feature_tags. If that list is empty, return [].

Return one JSON object with exactly these keys: {"species_id": <id|null>, "species_confidence": <0-1>, "wood_category_ids": [,...], "wood_category_confidence": <0-1>, "edge_type_term_id": <id|null>, "edge_confidence": <0-1>, "figure_term_ids": [,...], "figure_confidence": <0-1>, "feature_tag_ids": [,...], "feature_tag_confidence": <0-1>}

Runtime appends LISTS: (JSON of the five closed lists) plus SKU/length/thickness and the photos.

call2 seed. Write the long product description for the slab from the supplied photos and listing facts. The name and short description are already built, so do not repeat them. Use the brand voice and geo context given. The dimensions in the fact block are exact: use those strings and invent no numbers. Write prose a premium lumber buyer would read.

7. Prompt management

  • The active Call 1 and Call 2 revisions are editable through the §2 interface; saving creates a new revision.
  • A revision identifies its content, author, and timestamp; inference_log records the revision used for each call.
  • The revision interface requires authentication before it is exposed beyond the trusted network (METADATA-107).