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.
This commit is contained in:
Ty
2026-09-20 22:54:36 -07:00
parent 81be17d5cd
commit 7287a55707
8 changed files with 300 additions and 75 deletions
+3 -3
View File
@@ -144,9 +144,9 @@ block, and brand/geo context; no provider thread id and no raw Call 1 result. Re
and never touches dimensions. Cites METADATA-55, METADATA-65.
Call 1 result fields: `species_id`, `species_confidence`, `wood_category_ids`,
`edge_type_term_id`, `figure_term_ids`, `figure_confidence`, `grade_term_id`, `grade_confidence`,
`character`, `inclusions`, `voids`, `checks`. Free-text observations map to synced `feat-*` tags
only.
`wood_category_confidence`, `edge_type_term_id`, `edge_confidence`, `figure_term_ids`,
`figure_confidence`, `feature_tag_ids`, `feature_tag_confidence`. Feature tags are ids from the
synced `feat-*` set only (no free-text bags). Grade is never suggested.
Call 2 result field: `description`. The name and short description are assembled by the server from
the primary wood category's patterns, not returned by the call.
+54 -15
View File
@@ -46,20 +46,23 @@ true; also on demand or retry. With inference off it is skipped and the fields a
**Inputs.**
- The clean processed photos at 1024 px long edge or less.
- The synced taxonomy: species leaves, Edge Type, Figure, Grade, Thickness, Moisture terms, each
with its Woo id. These are the only legal choices.
- 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 synced lists; it never invents categories or
terms.
- Free-text observations (character, inclusions, voids, checks) are mapped to existing synced
`feat-*` tags only; Woo is authoritative for those tags.
- 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`;
`edge_type_term_id`; `figure_term_ids` + `figure_confidence`; `grade_term_id` +
`grade_confidence`; `character`, `inclusions`, `voids`, `checks`. Grade, edge, thickness, and
moisture are singular.
**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
@@ -110,11 +113,47 @@ 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.** Classify the slab's species, wood categories, edge type, figure, and grade from
the supplied photos, choosing only from the supplied synced taxonomy lists, and return the result
fields in §3 as JSON. Report a confidence for each classified field. Map free-text observations
(character, inclusions, voids, checks) to the supplied feature-tag list only. Invent no category or
term.
**`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": [<id>,...],
"wood_category_confidence": <0-1>, "edge_type_term_id": <id|null>, "edge_confidence": <0-1>,
"figure_term_ids": [<id>,...], "figure_confidence": <0-1>, "feature_tag_ids": [<id>,...],
"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