docs(phase2): reconcile requirements and migrate capabilities/contracts

Surface-matrix sweep of every source doc; added nine missed behaviors (METADATA-115, REVIEW-50, APP-55/60/65, SETTINGS-45 mode, Generate-text availability, defaults-off). 153 requirements, 0 coverage gaps.

Migrated capabilities to docs/capabilities/ and contracts to docs/contracts/; added WOO-API, API, DATA-MODEL, PROMPTS, UX, TEST-SPEC. Populated MILESTONES; branch-neutral trunk docs; renamed umbrella term to Woo Slab Taxonomy. Archived reconciliation working records under .audit/archive/.
This commit is contained in:
2026-09-18 21:02:06 -07:00
parent a8cc2f7596
commit 01aa4c52c3
53 changed files with 3186 additions and 817 deletions
+142
View File
@@ -0,0 +1,142 @@
# Data model contract
Status: SPEC · 2026-09-18. Store: SQLite.
## Requirements impact
| Requirement | Impact on this design |
|---|---|
| APP-5 | slab status enum and transitions |
| APP-20 | ids, timestamps, revisions |
| APP-40 | derived numbers stored, never recomputed |
| CAPTURE-25, CAPTURE-30, CAPTURE-70, CAPTURE-80, CAPTURE-85, CAPTURE-90, CAPTURE-95, CAPTURE-105, CAPTURE-115, CAPTURE-130, CAPTURE-135, CAPTURE-160 | slab and photo columns, units, PNG |
| METADATA-5, METADATA-10, METADATA-15, METADATA-30 | taxonomy cache tables and slab taxonomy columns |
| METADATA-35, METADATA-45, METADATA-55, METADATA-66, METADATA-105 | inference columns, prompts tables, logs |
| PUBLISH-25, PUBLISH-30 | purge on success, append-only log |
| REVIEW-10, REVIEW-25, REVIEW-45, REVIEW-50 | prose, price, SKU, field limits |
| SETTINGS-5, SETTINGS-10, SETTINGS-20, SETTINGS-25, SETTINGS-30, SETTINGS-35, SETTINGS-50, SETTINGS-51, SETTINGS-55, SETTINGS-65, SETTINGS-90 | settings, crypto, rates, taxonomy stamps |
## 1. Conventions
- Slab ids are client-generated UUIDv4; all other ids are integer autoincrement.
- Timestamps are UTC ISO-8601 text.
- Slab status is one of `draft`, `calibrated`, `ready`, `publishing`, `published`, `failed`.
- Inches are stored as the rounded 1/8-inch value the user entered.
- `sqft` and `bdft` are stored to 2 decimals half-up.
- `price` is stored to 2 decimals half-up.
- Multi-select taxonomy values are JSON arrays of Woo ids.
- Secrets are stored as `value_enc = nonce(12) || ciphertext`, AES-GCM; the master key is the env
`SLAB_AES_KEY` and is never in the DB.
- The local slab row is deleted on successful publish; `sync_log` and `inference_log` are
append-only and retained.
## 2. `slabs`
| Column | Type | Constraint / default |
|---|---|---|
| `id` | text | PK, client UUIDv4 |
| `status` | text | enum, default `draft` |
| `sku` | text | 3–24, alphanumeric and hyphen; unique locally |
| `length_in` | real | 1/8-inch step |
| `thickness_in` | real | 1/8-inch step |
| `sqft` | real | 2 dp |
| `bdft` | real | 2 dp |
| `width_min_in`, `width_max_in`, `width_avg_in` | real | 6-inch stations |
| `species_id` | int | FK `woo_categories`, one leaf |
| `wood_category_ids` | json | one or more leaf ids |
| `edge_type_term_id` | int | one term |
| `figure_term_ids` | json | one or more terms |
| `grade_term_id` | int | exactly one term |
| `thickness_term_id` | int | round-up band term |
| `moisture_term_id` | int | default kiln-dried term |
| `fig_tag_ids` | json | optional |
| `feat_tag_ids` | json | optional |
| `price` | real | 2 dp |
| `price_source` | text | `recommendation` \| `override` |
| `title`, `short_description`, `description` | text | required non-empty; title warn >60, short_description warn >160 |
| `content_source` | text | `manual` \| `llm` \| `template` |
| `species_confidence`, `figure_confidence`, `grade_confidence` | real | null below 0.7 |
| `inference_status` | text | null \| `inferring` \| `done` \| `failed` |
| `calibration_photo_id` | text | FK `slab_photos` |
| `client_rev`, `server_rev` | int | default 1 |
| `woo_product_id` | int | null until publish |
| `published_at` | text | null until publish |
| `created_at`, `updated_at` | text | UTC ISO-8601 |
No `inference_thread_id` column exists; provider threads are not used.
## 3. `slab_photos`
| Column | Type | Constraint |
|---|---|---|
| `id` | text | PK, UUID |
| `slab_id` | text | FK `slabs` |
| `seq` | int | capture order |
| `is_calibration` | int (bool) | exactly one true per slab |
| `original_blob` | blob | retained while draft/retry |
| `processed_blob` | blob | transparent PNG, alpha preserved |
| `width_px`, `height_px` | int | processed dimensions |
| `created_at` | text | UTC ISO-8601 |
The calibration photo exists; other batch photos are visual inventory only. Rows are purged on
successful publish.
## 4. `pricing_rules`
| Column | Type | Constraint |
|---|---|---|
| `id` | int | PK |
| `species_id` | int | FK `woo_categories`, UNIQUE |
| `price_per_bdft` | real | flat, no tiers |
| `created_at`, `updated_at` | text | UTC ISO-8601 |
## 5. Taxonomy cache
- `woo_categories` — species and wood-category leaves only; parents group and are never assigned.
- `woo_attributes` / `woo_attribute_terms` — exactly the five locked attributes Edge Type, Figure,
Grade, Thickness, Moisture, with their terms.
- `woo_tags` — only the fig-* and feat-* families; other store tags are ignored.
Rebuild is one transaction; on failure the previous cache is kept.
## 6. `settings`
| Key | Storage | Default |
|---|---|---|
| `woo_wp_username` | plain | — |
| `woo_app_password` | `value_enc` | — |
| `inference_base_url` | `value_enc` | — |
| `inference_api_key` | `value_enc` | — |
| `inference_model` | plain | — |
| `inference_enabled` | plain | `false` |
| `content_llm_enabled` | plain | `false` |
| `brand_voice` | plain | — |
| `geo_context` | plain | — |
| `woo_create_status` | plain | `draft` |
| `taxonomy_last_sync_at` | plain | — |
| `taxonomy_anchor` | plain | — |
`WOO_BASE_URL` is not a settings row; it is env, HTTPS only, read-only.
## 7. `prompts` and `prompt_revisions`
Prompts live in the database with all revisions; each call uses the active revision and the
history is retained.
- `prompts`: `id`, `name` (`call1` | `call2`), `active_revision_id`, `created_at`, `updated_at`.
- `prompt_revisions`: `id`, `prompt_id` FK, `content` text, `created_at`, `created_by`.
## 8. `sync_log`
Append-only; never deleted on publish. Columns: `id`, `slab_id`, `woo_product_id`, `status`
(`success` | `failed`), `payload_hash` (sha256 of the outbound payload), `message`, `created_at`.
## 9. `inference_log`
Append-only audit. Columns: `id`, `slab_id`, `call` (1 | 2), `prompt_revision_id` FK, `model`,
`request_payload`, `response_payload`, `latency_ms`, `created_at`.
## 10. Status transitions
`draft` → `calibrated` → `ready` → `publishing` → `published`, with `failed` reachable from any
step and retryable. `calibrated` is set when the draft uploads; `ready` requires the full set.