Drop the metadata_locked column + "Save and lock" UI end-to-end. The
review endpoint now builds the deterministic title/short_description on
every call; the owner's Create title / Create short desc buttons fire
the build and write the result (force-overwrite contract). commitReview
auto-fills only empty fields (no owner-clobber) and folds the
deterministic copy into its single PUT (kills the client_rev 409
cascade).
Taken wholesale from the branch: photo strip, wood primary/secondary,
server-side thickness band (hidden from UI, passed to Woo on publish),
and fixes #80/#82/#83/#84.
- backend: remove metadata_locked from schema.sql, db sentinels,
slabs.py client fields/exposure, review.py lock action; review
always computes title/short_desc
- frontend: slabs.ts + Review.svelte drop the lock model, add
Create-string workflow + wood primary + photo strip
- e2e: m3-create + review-photo-strip rewritten for the Create-string
contract; thickness-band test asserts absence (per #90)
- deploy: recreate LAN binds (override-m3.yml was absent); verify
metadata_locked gone, review builds title, PUT persists
Gates: backend 117/117, unit 88/88, tsc clean, e2e 6/6 (m3-create +
photo-strip). Live UAT verified at 192.168.1.202:10881.
- R1 soft delete: add deleted_at to slabs; exclude deleted rows from GETs
- R2 publish: terminal poll returns woo_product_id then the working row is
discarded; the app never deletes from WooCommerce (reworks PUBLISH-25)
- R3 prompts: SQLite is the point of record; file-based prompts superseded,
compose prompt mount removed
- R4 images: photo bytes are SQLite BLOBs; /images is a health probe + staging
Details recorded in .audit/m3-build-plan.md.
Check in implementable deploy/docker-compose.yml, .env.example, and Caddy
fragment. Store URL is env SoT (not a settings row). Application Password
setup stays in DEPLOYMENT §5 (issue #5).