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/.
8.1 KiB
Test spec contract
Status: SPEC · 2026-09-18 · reconciled against the finished PoR.
Defines the affirmative test bar. It cites requirement IDs; docs/REQUIREMENTS.md is normative.
The human walkthrough is docs/UAT-PRACTICE.md.
Requirements impact
| Requirement | Impact on this design |
|---|---|
| QUALITY-5, QUALITY-10, QUALITY-15 | TDD for the deterministic core; vectors TV-1..TV-10 |
| QUALITY-20, QUALITY-35, QUALITY-50 | inference-off suite, Woo-mock integration, Compose UI E2E |
| QUALITY-25, QUALITY-30 | evidence rules; Ty owns gate exit |
| QUALITY-40, QUALITY-45 | property checks and bdft identity |
| QUALITY-55 .. QUALITY-100 | pipeline vectors |
| QUALITY-105, QUALITY-110 | dishonest proxies; M3 exit evidence |
| QUALITY-115, QUALITY-120, QUALITY-125 | browser E2E, no raw codes, AES round-trip |
| APP-45, APP-55, APP-60, APP-65 | health, logging, accessibility, log redaction |
| SETTINGS-80, PUBLISH-30/31/35 | failure handling under test |
1. Layers and harness
| Layer | Written | Location | Rule source |
|---|---|---|---|
| Unit | TDD before the code exists | backend/tests/unit/, frontend/src/__tests__/ |
deterministic core and validation |
| API contract | with the feature | backend/tests/contract/ (pytest + httpx TestClient) |
docs/contracts/API.md |
| Integration | with the feature | backend/tests/integration/ (respx Woo mock) |
docs/contracts/WOO-API.md, docs/contracts/CONTENT-WOO.md |
| UI / E2E | with the feature | frontend/e2e/ (Playwright, Compose stack, mocked Woo) |
docs/contracts/UX.md |
| Ops | with deploy config | deploy/tests/ (shell) |
deploy/ |
Allowed results are pass, fail, not run, and optionally blocked. Every pass or fail
needs runner evidence; no evidence means not run. The only bug log is Gitea issues. Ty reads raw
results and owns gate exit; an agent never declares a gate green (QUALITY-25, QUALITY-30).
2. Fundamentals (FUND)
- FUND-1..4 — no browser/DOM/network deps in pure tests; semantic selectors; real Tab navigation; reactivity flush. (test practice)
- FUND-5, FUND-6, FUND-7 — Tab order, 320 px reflow, visible focus ring →
APP-60 - FUND-8..11 — app factory per test, lifespan, override cleanup, no real network (test practice)
- FUND-12, FUND-13, FUND-16 — FK and constraint enforcement, migration integrity (test practice)
- FUND-14 — WAL with no stale reads (test practice)
- FUND-15 — illegal status transitions rejected →
APP-5 - FUND-17 — fresh nonce per encrypt; tamper fails →
SETTINGS-25 - FUND-18 — ciphertext absent from GET; only configured booleans →
SETTINGS-75 - FUND-19 — missing key refuses startup →
SETTINGS-25 - FUND-20 — Basic Auth with application passwords over HTTPS, not consumer keys →
SETTINGS-15 - FUND-21 — 401/400/404 mapped, not passed raw →
APP-50 - FUND-22 — pre-create SKU lookup, duplicate race →
PUBLISH-15 - FUND-23 — timeouts/network errors graceful, no stack →
PUBLISH-30,PUBLISH-35 - FUND-24 — no secret material in logs →
APP-65 - FUND-25 — HTTPS, health through proxy, port collision →
OPS-5,OPS-15,OPS-20
3. Deterministic vectors (TV)
- TV-1 — green patch not touching the border survives; U2Net not invoked →
QUALITY-55 - TV-2 — dark interior wood survives; flood fill isolates border-connected regions →
QUALITY-60 - TV-3 — 96 in, 1.5 in, 0.64 sqft yields 0.96 bdft; 1 sqft at 1 in equals 1 bdft →
QUALITY-65 - TV-4 — 6 in stations on a 96 in axis report min, max, average →
QUALITY-70 - TV-5 — one square end, one 45 degree cut; axis follows prevailing length →
QUALITY-75 - TV-6 — 3:4 crop, 90 percent fill at extremes, transparent PNG, 800 px floor →
QUALITY-80 - TV-7 — undersized source warns, is not upscaled, not publishable until retake →
QUALITY-85 - TV-8 — 0.96 bdft at 12.50 gives 12.00; a 150.00 override is stored →
QUALITY-90 - TV-9 — 1 in rounds up into the synced Woo thickness band →
QUALITY-95 - TV-10 — half-up 2 decimal rounding cases →
QUALITY-100
Validation:
- SKU charset 3–24 alphanumeric and hyphen →
REVIEW-45 - title/short_description/description within limits →
REVIEW-50
AES:
- round-trip decrypt; ciphertext never in GET →
QUALITY-125,SETTINGS-75 - missing key refuses startup →
SETTINGS-25
API contract / health / draft:
GET /api/healthshape and non-200 on DB/volume failure →APP-45POST /api/v1/slabsmultipart returns 201 calibrated →docs/contracts/API.md,APP-5
4. Gate C and Woo
SLAB-UAT-*creates a draft regardless of setting →PUBLISH-10- duplicate SKU before create returns 409 with
edit_sku/open_existing→PUBLISH-15 - test-woo ok, resyncs taxonomy →
SETTINGS-40 - WOO_BASE_URL read-only, PUT rejected →
SETTINGS-5,SETTINGS-85 - startup refuses missing or http WOO_BASE_URL →
SETTINGS-10 - Woo create stores
woo_product_id, purges images →PUBLISH-25 - Woo 409 mapped to field recovery, draft retained →
PUBLISH-15 - taxonomy anchor unchanged on no-op, bumps on change →
SETTINGS-55 - failed publish marks failed, keeps photos, writes sync_log, retries to success →
PUBLISH-30
5. Inference
- with inference off: Call 1 skipped, no inference calls, suite passes →
METADATA-75,QUALITY-20 - test-inference returns ok, mode stateful/stateless, vision_capable →
SETTINGS-45 - test-inference fail blocks Call 2 only →
SETTINGS-45 - Call 1 at or above 0.7 pre-fills; below stays empty; override wins →
METADATA-45,METADATA-50 - Call 1 sends clean processed photos at 1024, synced taxonomy, user metadata →
METADATA-35 - Call 2 user-triggered only, fresh full context →
METADATA-55,METADATA-60 - model does not invent dimensions →
METADATA-65 - generation logged →
METADATA-66 - prompts stored with revisions →
METADATA-105
6. UI end-to-end (UIE / E2E)
- capture controls, overlay, axis, numbers, ready gates →
CAPTURE-40,CAPTURE-45,CAPTURE-50,CAPTURE-60,CAPTURE-70,CAPTURE-80,CAPTURE-85,CAPTURE-90,REVIEW-5,REVIEW-20 - review pre-fill and editability →
METADATA-45,REVIEW-40 - duplicate SKU, stale value, success, failure messages →
PUBLISH-15,PUBLISH-20,PUBLISH-25,PUBLISH-30,PUBLISH-35 - inference-off content path, Generate text disabled →
METADATA-70,METADATA-110 - settings screen and read-only URL →
SETTINGS-5,SETTINGS-15,SETTINGS-20,SETTINGS-30,SETTINGS-35,SETTINGS-65 - cross-browser capture through publish →
QUALITY-115
7. API surface
- revisions and conflict →
APP-20 - PUT stores derived, no recompute →
APP-40 - secrets absent from GET →
SETTINGS-75 - infer-taxon/content 202 and poll; timeout →
METADATA-35,METADATA-115 - publish preconditions →
REVIEW-5 - taxonomy sync, anchor, cache retention →
SETTINGS-50,SETTINGS-55 - delete soft, published undeletable →
docs/contracts/API.md - test-woo fails closed →
SETTINGS-80 - taxonomy re-pull and 1 hour publish refresh →
SETTINGS-60 - species picker synced only →
METADATA-5
8. Ops and instrumentation
- compose health, inventory, test-woo, draft status →
OPS-15,SETTINGS-40,SETTINGS-65,APP-45 - backup and restore retention and cycle →
OPS-30,OPS-35 - health non-200 on DB/volume,
woo_reachablefalse →APP-45 - request id in logs →
APP-55 - inference_log and sync_log written →
METADATA-66,PUBLISH-30
9. Purged cases
Removed because the behavior was superseded: four-knob cases (edge offset, feather), the shared
validation module and its 412 path, previous_response_id and the per-slab thread, "inventory
photos" as the Call 1 input, prompt files edited without restart, 80 percent / 1600 px crop values,
and manual override of the computed fields.
10. New cases
- keyboard tab order, focus ring, and 320 px reflow →
APP-60 - no secret material in any log output →
APP-65
11. Rules that do not change
Inference is optional and the full suite passes with it off. bdft = sqft × thickness_in, no
divide-by-12. The client is authoritative for deterministic math; the server stores the numbers.
No new product locks live in this document.