docs: Gate A freeze — AGENTS.md + hybrid Phase 0
Lock hybrid topology, Woo draft+SLAB-UAT-* UAT firebreak, client-authoritative TECH-SPEC math, and sequenced inference after Gate C. Supersede obsolete server-pipeline Phase 0 and flag Phase 2 offline/OCR/ruler as out of POC scope.
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
# AGENTS.md — SlabUploader
|
||||
|
||||
Working contract for coding agents. Read before writing code.
|
||||
|
||||
Status: **Gate A freeze** · signed 2026-08-31 PT · SoT: Gitea `Ty_Tech/SlabUploader` on **gitea-atd** (not mirrors).
|
||||
|
||||
---
|
||||
|
||||
## 0. Doc precedence (hard)
|
||||
|
||||
When docs disagree, use this order until stale docs are rewritten:
|
||||
|
||||
1. **`docs/TECH-SPEC-PIPELINE.md`** — deterministic math, image prep, constants, test vectors
|
||||
2. **`docs/ARCHITECTURE.md`** — hybrid topology, what-runs-where, secrets, status machine
|
||||
3. This **`AGENTS.md`** — hard rules for agents
|
||||
4. **`docs/DATA-MODEL.md`**, **`docs/OPENAPI.md`**, **`docs/CONTENT-WOO.md`**, **`docs/PROMPTS.md`**, **`docs/DEPLOYMENT.md`**
|
||||
5. **`docs/IMPL-PLAN.md`** — Phase 0 hybrid rewrite is authoritative; Phases 1+ TBD rewrite — **do not implement old Phase 0–2** (server happy-path pipeline, offline PWA, OCR, ruler)
|
||||
6. **PRD / README** — product intent only; do **not** implement lines that contradict TECH-SPEC or ARCHITECTURE
|
||||
|
||||
Known stale / do-not-implement without rewrite:
|
||||
|
||||
- PRD FR4 `bdft = sqft × thickness / 12` → **wrong**. TECH-SPEC: `bdft = sqft × thickness_in` (no `/12`).
|
||||
- PRD decision 15 “creds client-side” → **wrong**. Server AES-GCM only; never browser storage for secrets.
|
||||
- PRD / README “server does normalization / offline-first PWA / OCR / ruler” → superseded by hybrid + online-only MVP.
|
||||
- IMPL-PLAN Phase 0–2 text that describes server `pipeline/` CLI, ruler, offline PWA, Tesseract, OpenCV.js ruler → obsolete (Phase 0 rewritten 2026-08-31).
|
||||
- CONTENT-WOO / DEPLOYMENT smoke “pending” as default create → superseded: UAT uses **Woo draft** + `SLAB-UAT-*`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Topology (locked — hybrid)
|
||||
|
||||
**Client (SvelteKit) owns the happy path:**
|
||||
|
||||
- Capture 1–5 photos
|
||||
- Sheet detect + chroma-key / black threshold + sliders (sensitivity, edge offset, feather)
|
||||
- Mask overlay + **user confirm** before measurement
|
||||
- Length axis overlay (rotate / confirm)
|
||||
- sqft, bdft, 6" width samples
|
||||
- 3:4 transparent PNG, 80% fill at extremes, shorter side ≥ 1600 when source allows
|
||||
- Draft payload: originals + processed PNGs + length/thickness/SKU/sqft/bdft/widths
|
||||
|
||||
**Server (FastAPI) owns:**
|
||||
|
||||
- Store drafts / settings / taxonomy cache
|
||||
- **U2Net on demand only** (“Try harder” / coverage failure) — one photo in, mask out; sliders still apply on client
|
||||
- WooCommerce (taxonomy sync, SKU check, create product) — browser never calls Woo
|
||||
- Inference **proxy** (Call 1 / Call 2) — keys never in browser
|
||||
- Prompt files (server text files, read fresh)
|
||||
|
||||
Happy path never leaves the phone until the user continues after confirmed mask + numbers.
|
||||
|
||||
---
|
||||
|
||||
## 2. What NOT to build (early phases / MVP)
|
||||
|
||||
| Deferred / killed for early phases | Notes |
|
||||
|---|---|
|
||||
| Offline capture / PWA / IndexedDB sync | Online-only MVP |
|
||||
| OCR (SKU) | Manual SKU entry |
|
||||
| Ruler detection / OpenCV on client for scale | Manual length; scale = longest_axis_px / L |
|
||||
| Server-side happy-path pipeline | No server chroma-key / crop / bdft math as SoT |
|
||||
| Fake upscale / inventing pixels | Warn + retake if < 1600 after crop |
|
||||
| LoRA / fine-tune | Deferred |
|
||||
| Figure-/category-weighted pricing | v1.5 |
|
||||
| Auto-dimension overlay | v1.5 |
|
||||
| Bulk publish, staff roles, analytics, SKU update path | Non-goals |
|
||||
|
||||
---
|
||||
|
||||
## 3. Deterministic core (non-negotiable)
|
||||
|
||||
Encode TECH-SPEC exactly:
|
||||
|
||||
- **bdft = sqft × thickness_in** (identity: 1 sqft @ 1" = 1 bdft). **No `/12`.**
|
||||
- Units: inches in 1/8" steps; sqft/bdft 2 decimals; price half-up 2 decimals.
|
||||
- Manual length, thickness, SKU, price always win.
|
||||
- Image prep: sheet/sliders → mask confirm → length axis confirm → 3:4 PNG / 80% fill / ≥1600px when source allows.
|
||||
- **No inventing pixels. No fake upscale.** Undersized source → warn + retake; photo not publishable until retake.
|
||||
- Pricing: species `$/bdft` from Settings, seeded by Woo species sync; `rec = bdft × price_per_bdft`; user override sticks; missing rule → empty rec, manual allowed.
|
||||
- Port TECH-SPEC **TV-1…TV-9** (TV-10 only after TECH-SPEC defines it). Client (or shared pure modules the client uses) is authoritative for math; server **stores** client-sent numbers — does not recompute as SoT.
|
||||
|
||||
---
|
||||
|
||||
## 4. Secrets & settings
|
||||
|
||||
**Never in browser storage / JS bundles:**
|
||||
|
||||
- Woo consumer key + secret
|
||||
- Inference base URL + API key
|
||||
- AES master key (`SLAB_AES_KEY` env only; never in DB or repo)
|
||||
|
||||
**Server:** AES-GCM at rest in SQLite for Woo + inference secrets. Settings UI POSTs to FastAPI; server encrypts. All Woo and inference calls are server-side.
|
||||
|
||||
**Browser may persist (non-secret):** sheet mode, sensitivity, edge offset, feather (localStorage OK; reset-to-default required).
|
||||
|
||||
---
|
||||
|
||||
## 5. Woo UAT & create status (Ty locked 2026-08-31)
|
||||
|
||||
- Store: **PROD** `www.whidbeywoodstore.com`
|
||||
- Mid-phase UAT creates: Woo status **draft**, SKU prefix **`SLAB-UAT-*`**
|
||||
- Settings field **`woo_create_status`**: **`draft | publish`**, default **`draft`**
|
||||
- Hard rule: if SKU matches `SLAB-UAT-*`, force **Woo draft** even if Settings say publish
|
||||
- Final POC success: one real (non-UAT) SKU → **Woo publish** only after Ty review
|
||||
- Duplicate SKU → stop, surface error; no edit-same-SKU in MVP
|
||||
- After successful publish: purge originals + processed images on server
|
||||
- Do **not** conflate with slab lifecycle status (below)
|
||||
|
||||
---
|
||||
|
||||
## 6. Inference (inside POC, sequenced)
|
||||
|
||||
- Feature-flagged; **full suite must pass with inference OFF**.
|
||||
- **Gate C** claimable path: inference **OFF**; manual taxonomy + deterministic numbers + Woo draft path.
|
||||
- **Call 1 (vision) / Call 2 (text) only after Gate C is green, still inside overall POC** before “done” — not post-POC.
|
||||
- Call 1 auto only if `inference_enabled`; Call 2 never auto-fires (user taps Generate text).
|
||||
- LoRA deferred. No numeric/dimension invention by LLM; templates inject deterministic numbers.
|
||||
|
||||
---
|
||||
|
||||
## 7. Slab status machine (app-internal only)
|
||||
|
||||
`draft → calibrated → ready → publishing → published` (or `failed` with detail).
|
||||
|
||||
- **calibrated:** mask + axis confirmed; length/thickness/SKU entered; client computed sqft/bdft/widths; draft uploaded.
|
||||
- **ready:** mandatory fields filled (manual and/or Call 1); inference optional.
|
||||
- Inference does not gate publish.
|
||||
- Never confuse slab `draft` with **Woo draft** (`woo_create_status`).
|
||||
|
||||
---
|
||||
|
||||
## 8. Test & delivery expectations
|
||||
|
||||
- No feature without a passing test and shown execution output (PR/commit message).
|
||||
- Deterministic core unit-tested before UI consumes it.
|
||||
- One phase = reviewable, shippable increment; Ty exit-gates phases.
|
||||
- Phase naming: Phase 0–6 stay delivery chapters. **Phase 0 = Gates A+B.** **Gate C = early Phase 1** claimable publish slice.
|
||||
- Do not write secrets, real Woo keys, or AES keys into the repo.
|
||||
- Prefer fixing docs when code and locked decisions diverge — do not silently reintroduce `/12`, offline, ruler, or server happy-path pipeline.
|
||||
|
||||
---
|
||||
|
||||
## 9. Deploy sketch (see DEPLOYMENT.md)
|
||||
|
||||
- Target: `.201`, Docker Compose (`frontend` + `fastapi`) + Caddy → `slab.tyubumini.local` (LAN/Tailscale).
|
||||
- Inventory host ports/Caddy before binding (bolt.diy collision risk).
|
||||
- Health: `GET /api/health`.
|
||||
- Inference is a remote configurable endpoint, not on `.201` by default.
|
||||
+53
-21
@@ -1,6 +1,7 @@
|
||||
# Implementation Plan
|
||||
|
||||
Status: SPEC · 2026-08-24 · SlabUploader
|
||||
Status: SPEC · Gate A freeze 2026-08-31 · SlabUploader
|
||||
Phase 0 rewritten for hybrid topology (client-authoritative TECH-SPEC). Phases 1+ still contain stale offline/OCR/ruler/pending language — do not implement those lines; follow AGENTS.md.
|
||||
The build plan a professional (or a fresh Hermes session) executes against. Each
|
||||
phase has: goal, deliverables, acceptance criteria (testable), and exit gate.
|
||||
Ordering is by dependency — do not skip ahead. Definition of done for EVERY phase:
|
||||
@@ -14,27 +15,55 @@ Ground rules (from AGENTS.md):
|
||||
|
||||
---
|
||||
|
||||
## Phase 0 — Skeleton & deterministic core (server)
|
||||
Goal: repo scaffold + the tested deterministic pipeline, no UI, no Woo.
|
||||
## Phase 0 — Hybrid skeleton & client deterministic core (= Gates A+B)
|
||||
|
||||
Goal: scaffold the hybrid app and ship a **tested client-authoritative** TECH-SPEC
|
||||
pipeline (mask → axis → sqft/bdft → 3:4 PNG) plus a minimal FastAPI store/settings
|
||||
shell. No Woo publish, no inference, no offline/OCR/ruler.
|
||||
|
||||
**Gate A (docs):** AGENTS.md + this Phase 0 rewrite + review package locks (signed
|
||||
2026-08-31). **Gate B (infra/code):** items below.
|
||||
|
||||
Scope — in:
|
||||
- Repo layout: `frontend/` (SvelteKit), `backend/` (FastAPI), `deploy/` stubs; docs stay SoT.
|
||||
- Client pure modules implementing TECH-SPEC: constants, sheet/chroma/black + sliders,
|
||||
mask confirm hooks, length axis, scale, 6" widths, sqft, **bdft = sqft × thickness_in**,
|
||||
pricing rec from species $/bdft, 3:4 PNG / 80% fill / ≥1600 guard (**no upscale**).
|
||||
- FastAPI: app factory, logging, config, `GET /api/health`, SQLite + alembic skeleton,
|
||||
settings stub with AES-GCM round-trip (secrets never returned on GET), draft store stub
|
||||
(accept client numbers + files — store only, do not recompute SoT).
|
||||
- `deploy/docker-compose.yml`, `Caddyfile.fragment`, `.env.example` (placeholders only).
|
||||
- Unit tests for TECH-SPEC **TV-1…TV-9** (esp. TV-3 bdft, TV-6/7 crop/no-upscale, TV-8 pricing).
|
||||
- Fixture photo set for Ty Gate B review.
|
||||
|
||||
Scope — out:
|
||||
- Server happy-path pipeline / CLI that recomputes mask/crop/bdft as SoT.
|
||||
- Real U2Net (stub OK; on-demand later).
|
||||
- Woo create/publish, live taxonomy sync (mock/seed species list OK later).
|
||||
- Inference Call 1/2, LoRA.
|
||||
- Offline PWA, IndexedDB sync, OCR, ruler.
|
||||
- Fake upscale / inventing pixels.
|
||||
|
||||
Deliverables:
|
||||
- `backend/` FastAPI skeleton: app factory, health endpoint, config, logging.
|
||||
- `pipeline/` implementing TECH-SPEC: constants.py, ruler→scale, geometry, width
|
||||
sampler, bdft math, pricing, green-removal, crop/normalize, merch filter.
|
||||
- `db/`: schema.sql + alembic migration for all tables (DATA-MODEL).
|
||||
- `tests/`: port every TECH-SPEC test vector (TV-1…TV-9) to pytest; add property
|
||||
tests (bdft monotonic in inputs; width sampler returns 3–5 points; crop fill ∈
|
||||
[0.75,0.85]).
|
||||
- Dockerfile for backend; runs `pytest` in CI/local.
|
||||
- `frontend/` scaffold + deterministic modules + unit tests TV-1…TV-9.
|
||||
- `backend/` FastAPI health + settings encryption + draft persistence stub + schema migration baseline.
|
||||
- `deploy/` compose + `.env.example` + Caddy fragment.
|
||||
- Shown output in PR/commit: printed TV-3, TV-6, and TV-7 (no-upscale/retake) on **real fixtures**.
|
||||
|
||||
Acceptance:
|
||||
- `pytest` green, covering all 9 TVs + property tests; coverage of `pipeline/` ≥ 95%.
|
||||
- `GET /api/health` works on the dev container.
|
||||
- A fixture photo set (3–5 real slab photos) runs end-to-end through the pipeline
|
||||
CLI (`python -m app.pipeline.run <dir>`) and prints bdft/widths/normalized outputs
|
||||
matching hand-computed expectations.
|
||||
- Gate B: client (or shared pure) tests green for TECH-SPEC vectors; bdft identity holds
|
||||
(no `/12`); undersized source warns and refuses fake upscale.
|
||||
- `GET /api/health` up in compose over HTTPS hostname after `.201` inventory + Caddy merge.
|
||||
- Settings AES round-trip; secret fields never appear in GET.
|
||||
- Draft can store client-uploaded originals + PNGs + numbers without server recompute.
|
||||
- Coverage target: deterministic modules ≥ 95% where practical; property checks
|
||||
(bdft monotonic in thickness/sqft; fill band; no upscale path).
|
||||
|
||||
Exit gate: Ty reviews the pipeline CLI output on real photos; math confirmed.
|
||||
Exit gate: Ty confirms Gate B math/image prep shown output on real fixtures; health +
|
||||
encrypted settings + draft store stub demonstrated (curl or thin UI).
|
||||
|
||||
**Next (not Phase 0):** Gate C = early Phase 1 claimable publish — Woo **draft** +
|
||||
`SLAB-UAT-*` on prod, inference OFF. Call 1/2 after Gate C, still inside POC.
|
||||
|
||||
## Phase 1 — API surface (no Woo, no inference)
|
||||
Goal: full slab CRUD + photo upload + settings, backed by the Phase-0 core.
|
||||
@@ -55,6 +84,8 @@ Acceptance:
|
||||
Exit gate: Ty drives the API with curl through a full draft→ready cycle.
|
||||
|
||||
## Phase 2 — Frontend: capture & offline PWA
|
||||
> **SUPERSEDED for POC (Gate A 2026-08-31):** online-only; no OCR/ruler/offline PWA. Do not implement this section as written. Capture UX moves to early Phase 1 / Gate C shape per AGENTS.md.
|
||||
|
||||
Goal: mobile-first capture flow, fully offline, with the local light pass.
|
||||
|
||||
Deliverables:
|
||||
@@ -93,26 +124,27 @@ Acceptance:
|
||||
- Inference disabled → review screen fully functional with manual species/character.
|
||||
- Every field is editable and the override persists (asserted in a test).
|
||||
|
||||
Exit gate: Ty publishes a test slab to the real store as a **pending** product.
|
||||
Exit gate: Ty publishes a test slab to the real store as a **Woo draft** (`SLAB-UAT-*`) product.
|
||||
(Gate A lock: not pending/published for UAT.)
|
||||
|
||||
## Phase 4 — WooCommerce integration (real)
|
||||
Goal: production Woo sync, taxonomy, dedupe, logging (FR24–28).
|
||||
|
||||
Deliverables:
|
||||
- Woo client (httpx, Basic auth, timeouts), taxonomy sync, auto-assign, media upload,
|
||||
product create (status=pending default), dedupe, sync_log.
|
||||
product create via `woo_create_status` (default **draft**; `SLAB-UAT-*` forces draft), dedupe, sync_log.
|
||||
- `POST /api/admin/taxonomy/sync` against the real store.
|
||||
- Integration tests against a Woo mock (respx) for success + error + duplicate paths.
|
||||
- Partial-failure handling (orphaned media noted, per CONTENT-WOO §2.6).
|
||||
|
||||
Acceptance:
|
||||
- Real publish: product appears in store admin as pending, correct SKU/price/images/
|
||||
- Real UAT publish: product appears in store admin as **draft** under `SLAB-UAT-*`, correct SKU/price/images/
|
||||
category/tags; `woo_product_id` stored; `sync_log` written with payload_hash.
|
||||
- Duplicate SKU publish → 409, no second product created.
|
||||
- Woo error (bad creds / 500) → slab `failed` with detail; retry path works.
|
||||
- All Woo integration tests green (mock + one live smoke).
|
||||
|
||||
Exit gate: Ty verifies a real pending product in the store is correct.
|
||||
Exit gate: Ty verifies a real **Woo draft** `SLAB-UAT-*` product in the store is correct.
|
||||
|
||||
## Phase 5 — Inference (vision + optional content)
|
||||
Goal: scoped, toggleable inference with guardrails.
|
||||
|
||||
Reference in New Issue
Block a user