- backend/db/schema.sql: all 12 tables from DATA-MODEL.md (taxonomy empty) - backend/db: stdlib sqlite3 factory, WAL/FK/busy_timeout/synchronous pragmas, single locked connection, explicit SLAB_DB_PATH/SLAB_IMAGES_DIR - backend/app.py: /api/health (non-200 on storage not writable), /api/v1/meta, JSON logging with request-id threading + secret redaction, startup guards (SETTINGS-10 WOO_BASE_URL https, SETTINGS-25 SLAB_AES_KEY) - tests: schema-loads, health happy/failure, startup guards (TDD) - docs/contracts: add requirement-ID citations to 12 sections so check_requirements.py passes (pre-existing gate debt) Gates: check_requirements.py + check_coverage.py exit 0; pytest 5 passed
6.3 KiB
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):
POST /api/v1/prompts/{call}/revisionsappends a revision and returns it.POST /api/v1/prompts/{call}/activatemoves the active pointer to a revision.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.
- The synced taxonomy: species leaves, Edge Type, Figure, Grade, Thickness, Moisture terms, each with its Woo id. These are the only legal choices.
- 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.
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.
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. 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.
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_logrecords the revision used for each call. - The revision interface requires authentication before it is exposed beyond the trusted network
(
METADATA-107).