Files
SlabUploader/docs/contracts/PROMPTS.md
grokbot_ty 88278a55e8 fix(call2): no metadata dump in long description
Long desc is Hook + Benefits (+ brief trust close) only; forbid Full specs /
Attribute list / product-name header that re-lists DECLARED ATTRIBUTES or
DIMENSION FACT BLOCK. Defensively strip trailing Category:/Length:/Board Feet:
labeled dumps in parse.
2026-09-26 10:52:53 -07:00

12 KiB
Raw Permalink Blame History

Prompts contract

overnight-whole-app / Call 1 OUT: Call 1 (vision classification) is hard-disabled. POST /api/v1/slabs/{id}/inference/call1 returns 410 call1_disabled. UI triggers (Review "Suggest with AI", GenerateText classify) are removed. Call 2 (POST .../inference/call2, Review "Generate description") stays invokable. Call 1 seed text and prompt-revision APIs remain for documentation / future re-enable.

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. Call 2 writes both short_description (plain text, ~50 words) and description (HTML). The seed carries short/long writing structure (benefit→diff→trust short; Hook→Benefits→Specs→Trust long) and requires a JSON object {"short_description":"...","description":"..."}. Brand voice and geo stay Settings-injected at assemble time — not hardcoded in the seed. The server still assembles name deterministically (METADATA-55, METADATA-80); short may also be owner-edited or rebuilt via Create short desc. 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. Shipped text in backend/inference.py (CALL2_SEED), mirrored here for review.

Write listing copy for this slab for woodworkers choosing stock for a project. Audience: makers matching wood to a tabletop, bar, bench, or similar build — practical, material/figure/spec-forward. No lifestyle or marketing hype (avoid empty phrases like elevate, stunning, dramatic visual contrast). You write BOTH the short description and the long description.

PLAIN TEXT ONLY (short AND long):

  • Output plain text only. No HTML tags (<p>, <ul>, <li>, <strong>, <br>, etc.). No markdown bold/headers that look like markup (**bold**, # headers).
  • Structure the long description with newlines and - bullets when helpful.

Rules that always apply:

  • Dimensions in the DIMENSION FACT BLOCK are exact: use those strings; invent no numbers.
  • Use taxonomy names from DECLARED ATTRIBUTES; do not invent species, edge, figure, grade, moisture, or features.
  • Use the Brand voice and Geography sections when provided. If Brand voice is empty, stay neutral. Never invent return, warranty, or shipping policies.
  • The product name may already appear in DECLARED ATTRIBUTES — do not invent a new title.
  • Lead with usable traits (species, figure, size, edge, moisture, grade) and what the piece suits (tabletop, bar, etc.) without ad-copy fluff.
  • Specs live in taxonomy and dimension fields on the product. Do NOT restate DECLARED ATTRIBUTES or the DIMENSION FACT BLOCK as a labeled metadata list in the description (no Category:/Figure:/Edge:/Grade:/Moisture:/Length:/Board Feet: dump, no "Full specs" section, no "Maple Slab" attribute-header block). You may weave 1–2 key traits into prose or benefit bullets naturally.

SHORT DESCRIPTION (~50 words — most important on-page copy; plain text only):

  1. Lead with a practical outcome for a maker (what they can build / how the stock helps), not lifestyle hype and not a bare species list.
  2. Add the key differentiator or most important spec (figure, edge, size, moisture, grade).
  3. Close with a trust signal or concrete reason to choose this piece.

LONG DESCRIPTION (plain text only — newlines and - bullets; no HTML, no markdown markup). Hook + Benefits only (+ brief trust close). Do NOT add a Full specs / Attribute list / product-name header that re-lists DECLARED ATTRIBUTES or DIMENSION FACT BLOCK:

  1. Hook — one sentence on what the piece suits and its standout usable trait.
  2. Benefits — 3–5 bullets; each maker-useful trait first, then the supporting detail. Weave in at most 1–2 key traits naturally — not an exhaustive labeled catalog.
  3. Trust close (optional, brief) — return/warranty/brand; use Brand voice when present; otherwise a short neutral close with no invented policies.

Return ONE JSON object only (no prose outside JSON) with exactly these keys: {"short_description": "<plain text ~50 words>", "description": "<plain text long description>"}

Runtime appends DECLARED ATTRIBUTES (title + taxonomy; not a prior short), DIMENSION FACT BLOCK, and Brand voice: / Geo: from Settings (SETTINGS-30). The POST handler parses the JSON, strips any residual HTML to plain text, drops a labeled Category:/Length:/Board Feet: attribute dump if the model still emits one, and persists both fields.

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