- 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.
- PUBLISH: attempt-level failure wording, no image cap, failure triage rows
- METADATA: title rule is fallback-only (Call 2 not run)
- REVIEW: calculated widths/sqft/bdft not user mutable
- IDs now step by 5 per namespace; rule recorded in STRUCTURE.md
Reconciles the scattered requirements onto the owner-job namespaces.
- docs/REQUIREMENTS.md: 128 requirements across CAPTURE, METADATA, REVIEW,
PUBLISH, SETTINGS, APP, OPS, QUALITY
- docs/STRUCTURE.md: Test may be a path, a requirement ID, or - ;
a shipped path must exist
- tools/check_requirements.py: resolve test refs accordingly
- .audit/2026-09-18-reconciliation-decisions.md: full decision record plus
18 deferred rulings for the final cleanup pass
Gate: python tools/check_requirements.py -> PASS
Copy listing-copy/Woo payload spec from main. Lock {character} to the
primary Figure term name (Cathedral example). Lock categories[] to all
ready-set species and wood-category ids.
List the five locks from comparing CREATE.md to main technical docs
(categories payload, attributes shape, overlay upload, character
template source, server persistence).
Reorganize docs for humans: README map (goals / shipped / M3), PRODUCT
overview, and a specific CREATE.md that pulls Woo sync, metadata, pricing,
and inference requirements from main. Exit criteria is a slab submission-
ready for WooCommerce, proven with a SLAB-UAT-* draft. Add UAT-PRACTICE.
Add docs/CREATE.md as M3 SoT from Ty conversation (Woo attributes sync,
ready-set use, create, OpenAI Settings dependency). Point AGENTS/PRODUCT
here; mark main milestone splits obsolete for this branch.
Length dim already mask tip-to-tip (locked by test). Width labels move
axis-left off the wood via labelAt; font steps down to max(22, scale*1.0).
Inventory/overlay crop FILL 0.8→0.9; CAPTURE/PHOTOS docs match.
Lock Ty’s decisions: width stations start 6in from EXIF-oriented
photo bottom along the approved length axis; lineup is clean cal,
dimension overlay, then other batch PNGs in capture order.
sampleWidths used floor(L/6)+1 stations from t=0, so tapered tips
dominated min/max. Sample only interior stations at 6, 12, … ≤ L−6.
When L≤12 there is no interior span: every6In stays empty and
min/max/avg stay 0. CAPTURE.md Widths bullet matches.
sqft, bdft, scale, and inventory PNG are unchanged.
Product call for the WooCommerce redo. Calculate accepts
sources whose post-crop shorter side is at least 800px.
Warn copy and CAPTURE.md match. No upscale still holds.
Length axis keeps the approved mask, replaces Flip 180 with a ± angle
slider, and sets scale from wood span along the approved direction rather
than bbox.longSidePx. Widths still sample every 6 in perpendicular to that
axis.