- Add schema_version table; init_db detects a pre-M3/unknown DB (no version
row, or settings table missing the value column) and rebuilds to the clean
M3 schema, then stamps version 1
- _has_schema_version checks for a real row (empty table != versioned)
- _reset_for_tests checkpoints WAL before close (Windows handle release)
- TDD: test_schema_drift seeds the M2 settings shape, asserts rebuild + version
Fixes live 500 'no such column: value' on the UAT host (stale M2 slab_db volume).
Gates: check_requirements + check_coverage exit 0; pytest 14 passed.
The file restated facts owned by other docs and carried personal
references.
- Drop the status section, the agent-context block, the M3 scope prose, and
the 14-bullet invariants list; each restated docs/README.md,
docs/MILESTONES.md, or a docs/REQUIREMENTS.md row.
- Replace the ports and hosts paragraph with a pointer to docs/DEPLOYMENT.md
and deploy/INVENTORY.md.
- Correct the subagent rule to the real constraint: one at a time on the
single GPU. Subagents do coding work.
- Remove the name references.
- Keep the structure contract, the change-a-requirement procedure, and the
gate commands.
Two checks were added to catch drift between the point of record and the
docs that cite it.
- Check 11: a capability or contract doc must declare its IDs in a
Requirements impact table, and may cite only those.
- Check 12: a section that makes a behavior claim must cite an ID in that
section. External-shape sections are exempt.
CAPTURE.md and CREATE.md gained the impact-table rows the first check
requires. check_coverage is unchanged.
The file repeated requirement IDs on nearly every line, carried defensive
negations, mixed 'description' with 'long description', and left a cross
reference and the payload shape incomplete.
- Cite requirement IDs once in the Requirements impact table.
- Name the seven leaves as the synced WooCommerce wood-category leaves.
- Keep the length ft/in split with the short-description pattern it serves.
- Use 'description' only, matching the Woo field.
- Complete the cross references with section pointers.
- Follow the Woo v3 product shape and add an example submission whose
taxonomy values are placeholders, since the synced cache supplies them.
Docs written before this thread still carried the three-source copy model and
the Call 2 fields it implied.
- REQUIREMENTS.md REVIEW-10: title and short description are deterministic; the
description comes from the model or the server.
- CREATE.md: primary category declared before Call 2; deterministic copy; the
prompt revision interface; the slug; auth row in out-of-scope.
- API.md: infer-content inputs and result are the long description only.
- UAT-PRACTICE.md: the walk no longer tells the owner to leave copy for
templates.
- README.md: the deploy section duplicated docs/DEPLOYMENT.md and
deploy/INVENTORY.md; it now points at them.
- DEPLOYMENT.md: the prompt seed is stated per METADATA-105.
Both gates pass.
UAT requires prompt tuning, so the iteration system is M3; only the editing
UI is deferred.
- METADATA-105 now covers storage, append-only revisions, and recording the
revision used.
- METADATA-106 adds the REST revision interface (append, activate, read); no
prompt UI.
- METADATA-107 records the missing authentication as a later row; there is no
M4 yet, so the PoR carries it.
- PROMPTS.md owns the seed text as revision 0, the seed mechanism, and the
interface; sections renumbered after inserting them.
- DATA-MODEL.md §7 cites PROMPTS.md, adds content_hash, and states the
append-only rule.
- task_breakdown.md notes the S7 interface and the deferred auth.
155 requirements; both gates pass.
METADATA was ordered as it was written, not by topic, and used Call 1 /
Call 2 without defining them.
- Add a short METADATA preamble stating the inference flow: Call 1 vision
proposes taxonomy, the name and short description are deterministic, Call 2
writes the long description.
- Regroup the rows: taxonomy, then Call 1, then deterministic copy, then
Call 2, then cross-cutting.
- METADATA-70 said the deterministic name and short description were an
inference-off fallback; they are unconditional. It now covers only the
inference-off description.
- METADATA-81 folded into METADATA-80 (same rule, two strings).
- METADATA-45 now names the below-threshold outcome.
- METADATA-90 now states what the fact block drives.
153 requirements; check_requirements and check_coverage both pass.
Encode the recovered per-leaf title/short-description rule and the Call 2
input set into the point of record.
- REQUIREMENTS.md: METADATA-55 now produces the description only; METADATA-60
carries the ruled input set; METADATA-80 is the deterministic title; new
METADATA-81 is the deterministic spec-line short description; METADATA-85
selects the patterns; REVIEW-15 declares the primary before Call 2;
PUBLISH-55 carries an explicit name+SKU slug.
- CONTENT-WOO.md: per-leaf title and short-description catalog, slot order,
dimension placement, and the Cook Woods provenance.
- PROMPTS.md: Call 2 inputs and output; the deterministic patterns are cited,
not restated.
- CREATE.md, WOO-API.md, MILESTONES.md, task_breakdown.md updated to match.
Modeled on Cook Woods product-title form; the seven per-leaf prose templates
and Specialty cuts are parked in the M3 breakdown.
- DATA-MODEL.md: storage engine (stdlib sqlite3 + schema.sql, no ORM/migrations),
pragmas, per-test isolation.
- API.md: revision coupling, async job model, PUT check order, server-derived ready.
- PROMPTS.md: no prompt files ship; the DB is the only prompt source.
- docs/STRUCTURE.md: add a .planning/ registry (vision/roadmap/history/breakdown
roles), broaden the roadmap role, add enforcement items 8-10.
- tools/check_requirements.py: scan .planning/ too - every .planning/**.md must be
registered, registered files must exist, requirement rows rejected there.
- .planning/: PROJECT.md, ROADMAP.md, MILESTONES.md, and milestones/v0.5/M3/
{roadmap.md,task_breakdown.md}. M3 breakdown holds only the tasks; decisions live
in the contracts.
- docs/DEPLOYMENT.md: add the ops runbook (registered as ops).
- 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.
Lower the axial body threshold while retaining fringe rejection, minimize length-only tip inset, and make sheet sensitivity curves testable and conservative at zero.
PhotoStage used new Image() while mask worker and calculate used bare
createImageBitmap; Orientation-8 matched-set JPEGs can disagree across
those paths so the approved pink axis is not the overlay (ux,uy).
One decodeOrientedBitmap helper always requests imageOrientation
from-image (with bare fallback), wired into PhotoStage, mask.worker,
and session calculate/siblings.
Root cause: 0.2%/99.8% axial percentiles still included dense fringe past
the visible body; round line caps and scale-tied font overshot edges and
clipped width labels. Use across-width tip stations, inset length/width
ends for stroke/arrowhead, butt caps, inventory-capped font, axis-right
length label, clamp labels to PNG.
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 length dim to mask tip-to-tip (not oversized bbox), require width
labelAt on axis-left off the wood, smaller font contract, and 90% crop
fill extent. Red before green.