grokbot_ty
2f9b8ebd02
proto(woo): blocking setup gate; require X-Woo-* on Woo HTTP routes
...
Full-screen WooSetupGate on App mount when this browser lacks device WP
user + app password. Save + Test Woo dismisses only after a successful
test. Publish/test-woo auth failures reopen the gate.
Server: client_for_request requires X-Woo-* on publish, taxonomy sync,
and test-woo (401 woo_device_creds_required); health probe keeps
Settings. Optional SLAB_WOO_ALLOW_SETTINGS_FALLBACK for legacy tests.
See PROTOTYPE.md.
2026-09-26 19:20:16 -07:00
grokbot_ty
2f6335ec26
proto(woo): per-browser Woo creds via X-Woo-* request headers
...
Prototype routing so 2–3 owners can share one store URL with different WP
application passwords. Device creds live in localStorage; server uses
request override → Settings fallback and never writes overrides into the
Settings row. Inference stays on shared Settings.
See PROTOTYPE.md for UAT with two browsers and known LAN forge risk.
2026-09-26 12:26:21 -07:00
Ty
0c00d25cc7
fix(m3): Option A must-fix #79 #82 #83 #84 #89 #98
...
- #79 publish SKU/create via WooClient (User-Agent + typed 403 unrecoverable)
- #82 stale_field current_options from live taxonomy + owner labels
- #83 create allowlist/extra-key safe; taxonomy+enum 4xx on create
- #84 health woo_reachable real probe (non-failing); version 0.5.0-m3
- #89 review persists assembled title/short after taxonomy lock; UI applies
- #98 live-edge from synced term; attrs resolved by slug then name
2026-09-21 12:55:17 -07:00
Ty
fe82133ca4
fix(backend): #84 real woo_reachable, #83 reject unknown fields, #82 live taxonomy in stale_field, #80 persist review overrides
...
#84 : /api/health woo_reachable is now a real check (GET /wp-json/ with a
3s timeout) instead of a hardcoded False stub. Version bumped to 0.5.0-m3-s1.
#83 : POST /slabs rejects unknown (non-ALLOWED_FIELDS) keys with a 400
'unknown fields' error, instead of silently dropping them. The INSERT
binding count is now provably correct (no more assert needed).
#82 : stale_field 422 error now returns the LIVE taxonomy ids
(SELECT id FROM table) as current_options, plus the field name and
submitted value, instead of echoing the submitted value back.
#80 : regular review (no lock) persists owner overrides (price/sku/title/
short_description) from the payload to the DB via an UPDATE, so the
review endpoint is self-contained. server_rev is incremented on persist.
Tests: +3 (test_create_rejects_unknown_fields,
test_update_stale_field_returns_live_options,
test_review_persists_owner_overrides). 87/87 passing.
2026-09-20 23:38:29 -07:00
Ty
b99cbdf194
Fix 403 on test-woo: add User-Agent header, classify 403 as WooForbiddenError
...
WordPress security plugins (Wordfence, WAF) block the default
Python-urllib User-Agent with 403. Send a descriptive User-Agent on
all Woo requests. Also add WooForbiddenError so 403 is classified
distinctly from 401 (auth) per SETTINGS-80, and surface a clear
message in test-woo.
2026-09-20 07:59:00 -07:00
Ty
8a8a89ed3e
feat(inference): S7 Call 1/Call 2 + prompt revision REST + test-inference + Generate text UI
...
- backend/inference.py: prompt seed (rev 0) + append-only revision REST
(POST /prompts/{call}/revisions, /activate, GET; METADATA-105/106). Call 1 vision
classification (1024px processed photos + synced taxonomy, 0.7 confidence gate,
METADATA-35/40/45), Call 2 long description (user-triggered, METADATA-55/60/65),
inference_log per call (METADATA-66), inference-off server_description (METADATA-70),
test-inference probe (SETTINGS-45). Stdlib urllib, no new deps.
- frontend: create/inference/GenerateText.svelte (control visible only when content
enabled + endpoint reachable, METADATA-110; Call 2 + Call 1 buttons) + dev toggle.
- tests: 6 inference tests (seed+revision, call1 gate, call2 stores desc, off->409,
server desc, test-inference unconfigured).
Verified: pytest 54 passed; gates exit 0; npm build ok.
2026-09-19 17:04:01 -07:00
Ty
5e03f45660
feat(publish): S6 Woo create sequence + UAT draft + dup/stale/partial failure + Publish UI
...
- backend/publish.py: POST /slabs/{id}/publish. Sequence (PUBLISH-5): validate ready
set -> SKU lookup (409 on dup, PUBLISH-15) -> refresh taxonomy if >1h (SETTINGS-60)
-> resolve cats/tags/5 attributes -> upload processed PNGs -> POST /products ->
finalize (set woo_product_id, purge photos, PUBLISH-25). SLAB-UAT-* always draft
(PUBLISH-10). Failure: mark failed, retain photos, sync_log, plain recoverable/
unrecoverable message (PUBLISH-30/36/37/38). Partial (media ok, POST failed):
orphan media logged + manual cleanup note (PUBLISH-31). Payload: only non-null,
slug = name+sku, sold_individually true (PUBLISH-55/60).
- frontend: create/publish/Publish.svelte (slab id, publish, result + recoverable/
orphan tags) + dev toggle.
- tests: 5 publish tests (success+purge, UAT draft, not-ready 422, dup 409,
partial-media 502). Woo transport mocked.
Verified: pytest 48 passed; gates exit 0; npm build ok.
2026-09-19 17:00:26 -07:00
Ty
732310fdbe
feat(review): S5 pricing rules + deterministic title/short desc + server-derived ready + Review UI
...
- backend/pricing.py: /admin/pricing CRUD (one flat $/bdft per species leaf, SETTINGS-35).
- backend/review.py: POST /slabs/{id}/review -> deterministic title + short description
(7 leaf patterns, length ft/in split, thickness 1/8-in precision, METADATA-80/85/90),
price suggestion (bdft x species rate, REVIEW-25), server-derived ready + missing set
(REVIEW-5).
- frontend: create/review/Review.svelte (slab id, primary category, price override,
ready state + generated copy) + dev toggle.
- tests: 3 pricing + 4 review tests (title no-dims, ready set, price suggestion,
knife-blank dims).
Verified: pytest 43 passed; gates exit 0; npm build ok.
2026-09-19 16:52:33 -07:00
Ty
714a227e57
feat(photos): S3 multipart BLOB storage + original/processed GET + 410 after purge + attach UI
...
- backend/photos.py: POST /slabs/{id}/photos (multipart original+processed ->
slab_photos BLOBs, re-upload replaces), GET original/processed (image/png, 410
once purged), GET list. Cites CAPTURE-95/105/130, PUBLISH-40.
- frontend: create/photos/PhotoAttach.svelte (slab id, original/processed files,
calibration flag, lineup) + dev toggle.
- tests: 5 photos tests (upload+get both variants, 410 after purge, 404 slab,
reupload replaces, list).
Verified: pytest 36 passed; gates exit 0; npm build ok; live QA upload->200,
get original/processed->200, purge->410.
2026-09-19 16:47:07 -07:00
Ty
d83c9d5c21
feat(woo): S4 Woo client + taxonomy sync + test-woo + admin taxonomy
...
- backend/woo.py: stdlib urllib Woo v3 client. Basic-auth, HTTPS-only, X-WP-TotalPages
pagination, typed errors (CredentialsMissing/Auth/NotFound/Server/Connection),
injectable transport for tests, WP core media upload.
- backend/taxonomy.py: sync pulls categories/tags/attributes/terms into cache in one
commit (rollback keeps prior cache on failure); fig-*/feat-* tag scoping; stable
taxonomy_anchor hash; get_cached grouped admin view.
- backend/app.py: POST /settings/test-woo (fail-closed, resync on success),
GET /admin/taxonomy, POST /admin/taxonomy/sync (502 on Woo failure).
- frontend: Settings Test Woo button + result display.
- tests: 8 woo/taxonomy tests (auth header, non-https refusal, pagination, missing
creds, 401, scoped sync, failure-keeps-cache, anchor stability).
Verified: pytest 31 passed; check_requirements + check_coverage exit 0; npm build ok;
live QA test-woo fail-closed + sync 502.
2026-09-19 16:40:37 -07:00
Ty
cc5241f7da
feat(slabs): S2 CRUD + optimistic concurrency + soft delete + slab list UI
...
- backend/slabs.py: create (calibrated, client-derived stored as sent), list (excl
soft-deleted, most recent), get, update (single compare-and-set on server_rev,
409 revision_conflict / 409 duplicate_sku / 422 stale_field, status server-derived),
delete (soft, published rejected). Explicit column allowlists, parameterized SQL,
JSON array fields, commits.
- backend/app.py: wire slabs router.
- frontend: src/api/slabs.ts client + create/slabs/SlabList.svelte + dev toggle.
- tests: 9 slabs tests (create/dup/list/get/update/rev-conflict/dup-sku/soft-delete/
published-delete) with full taxonomy seeding.
Verified: pytest 23 passed; check_requirements + check_coverage exit 0; npm build ok.
2026-09-19 16:29:06 -07:00
Ty
b3380f3848
feat(settings): S1 AES-GCM crypto + Settings API/UI (masked write-only secrets)
...
- backend/crypto.py: AES-GCM (cryptography.AESGCM); key=base64(SLAB_AES_KEY)
must be exactly 32 bytes; value_enc=base64(nonce(12)||ct); DecryptError on tamper
- backend/settings.py: get_settings (secrets->{configured:bool}, woo_base_url env
read-only, flags default false), update_settings (rejects woo_base_url SETTINGS-85,
encrypts secrets, partial plain writes)
- backend/app.py: wire GET/PUT /api/v1/settings
- frontend/src/create/settings/Settings.svelte: masked form + partial PUT
- tests: crypto roundtrip/tamper, masked GET, encrypted PUT, reject woo_base_url,
flags default, decrypt-fail->configured:false (TDD)
Verified live: secrets round-trip configured:true with valid key; woo_base_url write
rejected 400; no secret leak in GET. Gates: check_requirements + check_coverage exit 0;
pytest 13 passed. Deploy+build on ubudual5060 (never Windows).
2026-09-19 15:48:42 -07:00
Ty
0eb2b0f697
feat(backend): S0 foundation (schema + stdlib sqlite3 db factory + health/meta + JSON logs)
...
- 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
2026-09-19 15:34:15 -07:00