docs(phase2): reconcile requirements and migrate capabilities/contracts

Surface-matrix sweep of every source doc; added nine missed behaviors (METADATA-115, REVIEW-50, APP-55/60/65, SETTINGS-45 mode, Generate-text availability, defaults-off). 153 requirements, 0 coverage gaps.

Migrated capabilities to docs/capabilities/ and contracts to docs/contracts/; added WOO-API, API, DATA-MODEL, PROMPTS, UX, TEST-SPEC. Populated MILESTONES; branch-neutral trunk docs; renamed umbrella term to Woo Slab Taxonomy. Archived reconciliation working records under .audit/archive/.
This commit is contained in:
2026-09-18 21:02:06 -07:00
parent a8cc2f7596
commit 01aa4c52c3
53 changed files with 3186 additions and 817 deletions
@@ -0,0 +1,76 @@
# Coverage gaps — serial worklist
- Date: 2026-09-18
- Branch: `docs/clean-main`
- Status: open worklist. Companion to `.audit/coverage/` and `tools/check_coverage.py`.
- Rule: work one entry at a time, top to bottom. Each decision is a ruling; record it, then
update the matching `gap` rows in the ledger to their resolution and re-run the gate.
The pilot slice (settings / auth / health) produced 12 `gap` atoms that collapse into the
seven distinct holes below. Each is a requirement the source material carries and
`docs/REQUIREMENTS.md` does not.
## GAP-1 — test-woo failure semantics
- Atoms: `tag:TEST-SPEC API-10`, `tag:OPENAPI test-woo-shape`, `prd decision-17`,
`tag:TEST-SPEC GC-3` (partial).
- Hole: the PoR says `test-woo` verifies the connection and resyncs (`SETTINGS-40`), but
nothing defines its result shape (`ok`, `detail`), that it fails closed on missing
credentials or non-HTTPS, or how an auth rejection differs from an unreachable store.
- Proposed home: `SETTINGS`.
- Status: open.
## GAP-2 — health endpoint semantics
- Atoms: `tag:TEST-SPEC H-1`, `tag:TEST-SPEC INS-1`, `tag:OPENAPI health`, `issue:#6`.
- Hole: `APP-30` names `/api/health`; nothing defines the body (`status`, `version`,
`woo_reachable`) or that health goes non-200 on DB/volume failure.
- Proposed home: `APP`.
- Status: open.
## GAP-3 — PUT /settings rejects a WOO_BASE_URL write
- Atoms: `tag:TEST-SPEC GC-4`, `tag:OPENAPI settings-PUT-reject`.
- Hole: `SETTINGS-5` makes the URL env-only and read-only, but nothing requires the settings
API to refuse an attempt to write it.
- Proposed home: `SETTINGS`.
- Status: open.
## GAP-4 — AES credential round-trip
- Atom: `tag:TEST-SPEC AES-1` (round-trip half).
- Hole: `SETTINGS-75` covers redaction; nothing asserts that an encrypted credential
decrypts back to its value.
- Proposed home: `QUALITY` (test obligation) over `SETTINGS-20/30`.
- Status: open.
## GAP-5 — upstream HTTP errors mapped to the envelope
- Atom: `tag:TEST-SPEC FUND-21`.
- Hole: publish field errors are mapped; there is no general rule that a 401/400/404 from
Woo is turned into the uniform envelope rather than passed through.
- Proposed home: `APP` (alongside `APP-35`).
- Status: open.
## GAP-6 — no app-level auth
- Atom: `prd no-app-auth`.
- Hole: no row states that the app has no login of its own and relies on network plus HTTPS.
- Proposed home: `OPS`.
- Status: open.
## GAP-7 — httpx timeout values
- Atom: `cur:CONTENT-WOO httpx-timeouts`.
- Hole: connect 10s / read 60s exist only in the contract draft.
- Proposed home: contract detail, not a requirement: record in `docs/contracts/` in step 3
and mark the ledger atom `dropped` with rationale.
- Status: open.
## GAP-8 — prompt storage
- Atom: `tag:DATA-MODEL prompt-files` (PROMPTS source still to walk).
- Hole: the source docs put prompts in `backend/app/prompts/`, bind-mounted read-only, read fresh
per call. Ruling 2026-09-18: prompts live in the DB with all revisions. No PoR row yet.
- Proposed home: `METADATA` (prompt management) or `SETTINGS`; resolve during the PROMPTS walk.
- Status: resolved 2026-09-18 — `METADATA-105` (prompts stored in the DB with all revisions).
@@ -0,0 +1,183 @@
# Migration TODOs — source docs
- Date: 2026-09-18
- Branch: `docs/clean-main`
- Purpose: edits deferred until Phase 2 step 3, when the capability and contract docs are
migrated into `docs/capabilities/` and `docs/contracts/`, made branch-neutral, and
converted to cite requirement IDs.
- Rule: these docs are not edited now. `REQUIREMENTS.md` is the only normative text and is
already correct for everything below.
## CAPTURE.md
1. Line 16, "Length of the slab is aligned with the long side of the picture" — ruled dead.
Remove.
2. Lines 128–129, the `kind=inventory` role label — discarded. The "first inventory photo is
the measurement reference" half is `CAPTURE-115`; keep it as a citation, drop the label.
3. Line 140, editor/storefront alpha presentation — discarded.
4. The sensitivity mapping (line 69) and display/source-pixels rule (lines 58–62) are now
`CAPTURE-41` and `CAPTURE-141`; cite them instead of restating.
5. Line 82 busy mark ("more than a fraction of a second"; as-built is 300 ms) — ruled a
nit, not a requirement. Leave as design prose or drop.
## CREATE.md
1. Grade cardinality: change "1 or more" to 1 in all three places (attributes table,
ready set, data shape). Ruling: Grade is exactly one.
2. `fig-*` cardinality: change "1 or more / required" to optional in the tags table and the
ready set. Ruling: tags optional; the Figure attribute is at least one.
3. Ready-set images: change "at least one inventory PNG" to two (clean calibration plus its
dimension-overlay copy). Ruling: `REVIEW-5` is the PoR.
4. Remove "cap at 5 images" from the create sequence.
5. Remove "user typed widths/sqft/bdft wins"; the calculated fields are read-only.
6. Fix the Call 2 line so the model writes the title/description and the deterministic
template is the fallback, not the assembler.
## CONTENT-WOO.md
1. Em dash in the title template and example → hyphen.
2. "Templates (always on)" and "templates inject those numbers after the prose comes back" →
template is the fallback only; the model writes when Call 2 runs.
3. `fig-*` "1+ required" and the ready set including `fig-*` tags → tags optional.
4. "≤5 inventory photos" → no cap; drop the "only `kind=inventory`" clause.
5. The empty `attributes` element shape is the known deferred decision; keep the placeholder.
## PHOTOS.md
No changes. Overlay legibility and arrow/text drawing detail were ruled design, not
requirements.
## TEST-SPEC.md (→ `docs/contracts/TEST-SPEC.md`)
1. Migrate and cite requirement IDs; drop the pre-ID source-doc references.
2. Purge superseded cases: UI-1, UIE-9, UIE-10 (four knobs); V-3, API-8 (validation module);
C2-2 (`previous_response_id` / thread); C1-1 (image source); C2-4 (prompt files); TV-6, TV-7,
E2E-5 (80 percent / 1600 px); UIE-1, E2E-4 (computed override).
3. Add cases for the two new rows: `APP-60` (keyboard, focus ring, 320 px reflow) and `APP-65`
(no secret material in logs).
## IMPL-PLAN.md (retired)
1. Retire `docs/IMPL-PLAN.md`. Phases and Gates A/B/C are superseded by `MILESTONES.md` plus the
PoR; acceptance and test obligations are QUALITY rows.
2. Superseded: four knobs; "1–5 photos"; 80 percent / 1600 px; calculated-field override; portable
context and the stateful probe; prompt files.
## ARCHITECTURE.md
1. §1, §2, §4 "four knobs" including Edge offset and Feather — controls are exactly Sheet and
Sensitivity (`CAPTURE-40`).
2. §2 "1–5 photos" — one or more (`CAPTURE-25`).
3. §6.3 ready set requires 1+ `fig-*` tag and 1+ grade — tags are optional and grade is exactly
one (`METADATA-30`, `METADATA-15`).
4. §8/§9 shared validation module, `validation_hash`, 412, stateful/stateless mode, and
per-slab thread — ruled cut 2026-09-18; thread work is out of the MVP and test-inference no
longer returns mode.
5. Retire `docs/ARCHITECTURE.md`: its testable rules are APP/CAPTURE/SETTINGS rows, and the
topology is covered by those plus `deploy/`.
6. §3.4 Call 1 image input "all originals downscaled to 1024" → clean processed photos
(`METADATA-35`).
## UX.md (→ `docs/contracts/UX.md`) and UX-DESIGN.md (retired)
1. Migrate `docs/UX.md` to `docs/contracts/UX.md`: branch-neutral, cite requirement IDs, do not
restate rules.
2. Retire `docs/UX-DESIGN.md` (non-normative). Fold the "AI" badge, first-run card, separate
Title/Description screen, and error-state copy into the UX contract.
3. Superseded in UX.md: four knobs → two; "1 to 5 photos" → no cap; "no calibration photos" → the
calibration photo exists; 80 percent / 1600 px → 90 percent / 800 px; calculated-field override
path → read-only; grade 1+ → exactly one; `fig-*` 1+ → optional; "templates always run" →
template fallback; "title/short/description not required to reach ready" → required
(`REVIEW-10`); `short_title` → `short_description`.
## TECH-SPEC-PIPELINE.md (retired)
1. Retire `docs/TECH-SPEC-PIPELINE.md`. Its deterministic rules are CAPTURE; its ten vectors are
QUALITY. Fold any wanted algorithm detail into the CAPTURE capability doc.
2. Superseded: 80 percent fill and the 1600 px floor → 90 percent and 800 px; four knobs → two;
the auto-dimension overlay is no longer v1.5 (it shipped).
## PROMPTS.md (→ `docs/contracts/PROMPTS.md`)
1. Prompts move from server text files to the database with all revisions (`METADATA-105`): drop
the read-only mount, host-editing, and reset-to-default script.
2. Remove `previous_response_id`, the portable-context machinery, and the shared-validation rules
from the Call 2 inputs.
3. "1–5 inventory photos" → no cap (`CAPTURE-25`).
4. Example title uses an em dash and a multiplication sign → hyphen separator; snap `short_title`
to `short_description`.
## DEPLOYMENT.md (retired)
1. Retire `docs/DEPLOYMENT.md`. Its testable rules are OPS/SETTINGS; its operational facts live in
`deploy/` (`INVENTORY.md`, `docker-compose.yml`, `Caddyfile.fragment`, `RELEASE-PROCESS.md`).
2. Fold any still-useful prose into `deploy/` (the deploy README is the natural home).
3. Repoint the UAT-PRACTICE references from `docs/DEPLOYMENT.md` §1/§3/§5/§8 to `deploy/`.
4. Superseded: `output_px_min 1600` → 800 px floor (`CAPTURE-105`); "prompt files live in git and
need no backup" → prompts live in the DB with all revisions (GAP-8).
## DATA-MODEL.md (→ `docs/contracts/DATA-MODEL.md`)
1. Grade "1+" → exactly one; `fig_tag_ids` "1+" → optional.
2. `output_px_min 1600` and `fill_target 0.80` → 800 px floor and 90 percent fill.
3. "Only inventory photos. Calibration photos do not exist." → the calibration photo exists; other
batch photos are visual inventory only (`CAPTURE-115`).
4. "No hard deletes for slabs (audit)" → the local slab row is deleted on successful create
(`PUBLISH-25`).
5. Remove `inference_thread_id`; thread work is out of the MVP.
6. Prompt files: replace the bind-mounted text files with prompts stored in the DB, all revisions
(PoR row pending the PROMPTS walk).
7. `short_title` → `short_description` (Woo canonical).
## OPENAPI.md (→ `docs/contracts/API.md`)
1. Field name `short_title` → `short_description` (Woo canonical). Applies to the schema, read
model, Call 2 result, and examples.
2. `fill_target 0.80` and `output_px_min 1600` → 90 percent fill and an 800 px floor
(`CAPTURE-100`, `CAPTURE-105`).
3. Remove the validation module endpoint, `validation_hash`, and the 412 path (ruled cut).
4. Remove `previous_response_id`, the per-slab thread, and `mode` from test-inference; Call 2 is
a fresh full-context call.
5. Grade cardinality "1+" → exactly one; `fig-*` "1+" → optional.
6. The taxonomy-sync example key `synced_at` should be `taxonomy_last_sync_at`.
7. Call 1 image input for infer-taxon: original photos → clean processed photos (`METADATA-35`).
## PRODUCT.md
1. Line 19, "One or more `fig-*` tags" — tags are optional per `METADATA-30`. Change to
optional.
2. Line 23, "Measured values feed title and description templates" — template is the fallback;
the model writes when Call 2 runs. Cite `METADATA-60`, `METADATA-70`, `METADATA-80`. Same
conflict in the decision-rights table, line 37 ("Templates from listing facts").
3. Line 20, "short title" — stale wording; the field is `short_description` (`REVIEW-10`).
4. Branch-neutral: line 1 "Milestone status on `m3-ds`", and line 66 "behavior ... taken from
`main`". Remove branch names.
5. Line 25, umbrella term "Woo attributes" → "Woo Slab Taxonomy" (see cross-cutting rename).
## README.md
1. Branch-neutral: line 1 title "Docs map (branch `m3-ds`)" and line 44 "copied into
`docs/CREATE.md` from `main`". Remove branch names.
2. Line 39, umbrella "Woo attributes" → "Woo Slab Taxonomy" (see cross-cutting rename).
## UAT-PRACTICE.md
1. Line 100, "four knobs: Sheet, Sensitivity, Edge offset, Feather" — controls are exactly Sheet
and Sensitivity; Edge offset and Feather are removed (`CAPTURE-40`).
2. Line 97, "1 to 5 photos" — no cap; `CAPTURE-25` is one or more.
3. Line 122, "at least one figure, at least one grade" — grade is exactly one (`METADATA-15`).
4. Line 126, "`fig-*` tags. Pick at least one." — tags are optional (`METADATA-30`).
5. Branch-neutral: line 14 "On branch `m3-ds`". Stale refs to `docs/DEPLOYMENT.md`, `docs/UX.md`,
`docs/TECH-SPEC-PIPELINE.md`, `docs/IMPL-PLAN.md` in the "where each rule lives" table.
## Cross-cutting: "Woo Slab Taxonomy" rename
Ruling 2026-09-18: the umbrella package term is **Woo Slab Taxonomy**; canonical Woo
attributes (the five) keep the name.
- Rename umbrella occurrences: `AGENTS.md:48`, `PRODUCT.md:25`, `CREATE.md:7`, `CREATE.md:34`,
`CREATE.md:50` (heading), `CREATE.md:261`, `CREATE.md:397`, `README.md:39`.
- Keep "Woo attributes" where it means the canonical five: `CREATE.md:61`,
`CONTENT-WOO.md:121`.
- Give the term one glossary home in the step-3 contract docs; make PRODUCT/AGENTS reference
it instead of redefining.
@@ -0,0 +1,211 @@
# Requirements reconciliation — decision record
- Date: 2026-09-18
- Branch: `docs/clean-main`
- Participants: Ty + opencode
- Status: working record. Gets distilled into `docs/REQUIREMENTS.md`, then retired.
This captures the decisions made while consolidating the scattered requirements, so
context is not lost between sessions. Loose ends are collected in section 16.
## 0. Resume here (for a new session)
**SUPERSEDED 2026-09-18. Read `.audit/2026-09-18-session-handoff.md` instead.**
This section is kept only so the history below still reads correctly. The current state,
locked rulings, gate output, and next steps all live in the handoff. Everything below this
point is the decision log from the original reconciliation, not the current resume point.
## 1. Why this exists
Requirements are scattered across layers of docs (old `main` specs, current branch docs,
`archive/`), with duplicates and contradictions. Goal: one clean `main` holding all shipped
code plus one reconciled requirement set, with M3 scoped as a subset of it. Coding is paused
until that exists.
## 2. Git state established
1. `pre-simplification` tag created at `13bfa792bb3ed968b333675c85bcec0c451e2635` (old main tip; retains the deleted specs: ARCHITECTURE, IMPL-PLAN, OPENAPI, DATA-MODEL, TEST-SPEC, UX, UX-DESIGN, TECH-SPEC-PIPELINE, DEPLOYMENT, PROMPTS, Build-release-standard).
2. `main` fast-forwarded to `d754cac` (the M1>M2>M3 code line). `main` now holds all shipped code plus current docs.
3. Local `m3-ds` created, tracking `origin/m3-ds`.
4. Phase 1 scaffold committed as `b42e3cb` on branch `docs/clean-main`.
5. Nothing pushed. `origin/main` still at the old tip until we decide to push.
## 3. Process rules adopted
1. Coding is paused until the requirement set is reconciled.
2. Requirements live only in `docs/REQUIREMENTS.md`, one row per requirement, with stable IDs.
3. Milestones are expressed as explicit subsets of requirement IDs (`docs/MILESTONES.md`).
4. Conflict resolution rule: current/later docs plus the code that actually runs beat the tag and `archive/`. "Typically later docs prevail."
5. The structure is enforced by `tools/check_requirements.py` (registered docs, unique IDs, traceability).
6. Verification discipline: no "done" without raw evidence; CI is the only mechanical gate.
## 4. Namespaces (owner jobs, not tech layers)
1. `CAPTURE` — ecommerce-ready pics: intake, pick calibration photo, BG removal, crop, axis, length/width, calculations, inventory PNG, dimension overlay, lineup.
2. `METADATA` — building the listing: attributes and tags, title, short/deep description, the two inference calls.
3. `REVIEW` — confirm and correct: confidence display, field gating, tweaks, per-slab price suggestion and override, ready gate.
4. `PUBLISH` — WooCommerce create, draft/live, duplicate SKU, cleanup.
5. `SETTINGS` — configured before the session: Woo connection, inference config, species `$/bdft` rates, brand/geo.
6. `APP` — foundation: device draft, slab status, resume, server seams, secret handling.
7. `OPS` — foundation: deploy, hosts, release, UAT.
8. `QUALITY` — foundation: test obligations, vectors, anti-metrics.
## 5. Capture decisions
1. Mask controls are exactly two: `Sheet` (auto/green/black) and `Sensitivity` (0–100). Edge offset and Feather are dropped. The Sheet toggle itself is a candidate for removal (auto-detect stays).
2. Sensitivity changes are debounced 2000 ms; a Sheet change runs an immediate pass.
3. The owner uploads all photos of the slab, then selects one as the calibration photo. That photo drives every downstream step, is duplicated with dimensions added, and becomes the first showcase image.
4. Crop is 90% fill, shorter side at least 800 px when the source allows (shipped values beat the old 80%/1600).
5. Length and thickness are the only user-set numbers. Widths, sqft, and bdft are computed from the approved mask and are immutable in production (no typed override).
6. Widths are sampled every 6 inches along the approved axis, dropping the first and last 6 inches.
7. Thickness band uses the round-up model: measured `1"` lands in the `1–1.5"` store band.
8. Woo image order is locked: clean calibration PNG, then dimension-overlay copy, then remaining batch photos in the order added. Minimum two images per listing; no upper cap.
## 6. Ready set (submission-ready)
Required:
1. At least two images — clean first pic plus its dimension-overlay copy.
2. `sku` matching `[A-Z0-9-]{3,24}`.
3. `length_in` and `thickness_in`.
4. Widths / sqft / bdft (computed, immutable).
5. `categories` — exactly one species leaf.
6. `categories` — at least one wood-category leaf.
7. `attributes[Edge Type]` — one term.
8. `attributes[Figure]` — at least one term.
9. `attributes[Grade]` — exactly one term.
10. `attributes[Thickness]` — one term (round-up band).
11. `attributes[Moisture]` — one term, default kiln-dried.
12. `regular_price`.
13. `name`, `short_description`, `description`.
Optional: all Woo product tags (figure family and features family).
Woo schema field mapping lives in section 6 of this record and will become the `METADATA` requirements.
Note: title / short description / description are required on the product. Because deterministic templates are the inference-off fallback, they are guaranteed non-empty at create.
## 7. Taxonomy and categories
1. Categories sync from Woo; the product is assigned to leaf categories. Parents are never assigned but matter in context: the site shows them (breadcrumbs/filters) and Call 2 receives the parent path as context.
2. Species is exactly one synced leaf. Wood category is one or more synced leaves.
3. In review, the owner designates a primary wood category and any secondary ones. Default primary is the first category selected. How the owner corrects it, and how they stay aware of it, is a UX problem deferred to design.
4. Primary drives the title. Primary plus secondary drives the description prose.
5. The primary leaf selects a specialized Call 2 prompt. This is the "common pattern."
6. Wood-category leaves: Knife blanks, Specialty cuts, Dimensional wood, Live edge wood, Bowl blanks, logs and caps, Pen blanks, Pepper mill blanks. All are settled prose/prompt work items except `Specialty cuts`, which is parked.
7. All Woo product tags are optional. Tags come from the synced Woo set; no hardcoded names or prefixes. Wrinkle: one figure tag is bare `fig` (Figured), so a `fig-*` glob would drop it — the filter must be data-driven.
8. Current tags. Features: `feat-mincr` (Crack/Check minor), `feat-resin` (Resin Ready). Figure: `fig` (Figured), `fig-brdseye`, `fig-chatoy`, `fig-crotch`, `fig-curl`, `fig-fback`, `fig-flame`, `fig-hfig`, `fig-marbled`, `fig-quilted`, `fig-splt`.
## 8. Locked attributes
1. `attributes[Edge Type]` — 1 term.
2. `attributes[Figure]` — at least 1 term; includes `plain` for basic slabs; never left empty.
3. `attributes[Grade]` — exactly 1 term.
4. `attributes[Thickness]` — 1 term, round-up band.
5. `attributes[Moisture]` — 1 term, default kiln-dried, never inferred.
6. Missing attributes or terms are skipped, never created. v1 does not invent taxonomy.
## 9. Text generation (Call 2)
1. Call 2 produces `name`, `short_description`, and `description`.
2. The template is a consistency/style guide in the prompt; the model has creative license. It is not assembled deterministically in code.
3. With inference off, the deterministic template is the fallback that fills those three fields.
4. Call 2 receives all metadata confirmed or changed in review — not the raw Call 1 suggestions.
5. Dimensions are supplied as a literal fact block (species, figure term, length, thickness, average width, width min–max, board feet). The model uses those exact strings and invents no numbers.
6. There is no `L × W × T` rectangle assumption; slabs are irregular and width varies.
7. The dimension-overlay image is not sent to the model.
8. A post-check for number drift is parked as `later`; if it is ever added it is plain deterministic comparison, not an AI call.
9. The title separator is a hyphen: ` - `.
## 10. Inference transport
1. Calls are asynchronous: the request returns `202`, the client polls and shows phase feedback.
2. Phases: uploading, analyzing, still working. Polling is the heartbeat that distinguishes dead connectivity from a working model.
3. Tunable defaults: ack 15 s, upload-stall 20 s, overall inference deadline 120 s after ack, poll every 2 s backing off to 10 s.
4. On timeout or failure, fail gracefully with a plain message and a Retry action. Retry is offered only if `test-inference` previously passed. A retry replaces any in-flight job (idempotent).
5. Inference input is the clean processed image (masked, cropped), composited on soft white, no alpha, downscaled to at most 1024 px long edge, JPEG quality 80.
6. Only the pixel cap is exposed in Settings. JPEG quality 80 lives in a server config file.
7. Call 1 and Call 2 both receive the images. Call 2 additionally receives the literal fact block.
8. Provider threads are dropped; always full resend to the provider.
9. Inference never blocks create and never auto-publishes.
## 11. Prompt management
1. Prompts are stored in SQLite as immutable revisions, seeded from bundled repo defaults on first run.
2. Saving appends a revision; an active pointer selects which revision is live.
3. Reset to default re-activates the bundled default; reset to a revision re-activates that revision.
4. Each inference call records the revision id/hash it used.
5. A runtime debug flag gates both the Advanced settings UI and the prompt-write endpoints. Single build, not two.
6. This is post-M3 (`later`).
## 12. Pricing
1. A flat `$/bdft` rate per species is configured in Settings, matched to a synced species leaf. No tiers in v1.
2. The per-slab suggestion is `bdft × rate`; the owner may override and the override sticks. No rule means an empty price the owner types.
3. The price field and its suggestion live in the review screen.
## 13. Publish
1. Create sequence is the documented one: validate the ready set, look up the SKU (stop if it exists), refresh taxonomy if older than one hour, resolve categories/tags/attributes, upload inventory PNGs, `POST /products`, then finalize.
2. On success the local slab row is deleted. WooCommerce is the only source of truth; `sync_log` is retained; photos are purged; the device draft is cleared.
3. `SLAB-UAT-*` always creates a Woo draft.
4. A duplicate SKU blocks create; there is no update path.
5. A stale value on submit is a field-level error telling the owner to pick from the current list.
## 14. Settings
1. Compose env: `WOO_BASE_URL` (https only), `SLAB_AES_KEY`.
2. Encrypted in SQLite: `woo_wp_username`, `woo_app_password`, `inference_base_url`, `inference_api_key`.
3. Plain settings: `inference_model`, `inference_enabled`, `content_llm_enabled`, `woo_create_status` (default draft), `brand_voice`, `geo_context`.
4. Derived: `taxonomy_last_sync_at`, `taxonomy_anchor`.
5. Auth is a WordPress application password for a dedicated low-privilege user; not consumer keys, not the login password.
## 15. Scope mapping
Shipped: M1 Capture, M2 Photos, capture knob prefs.
M3: store-connection and AI-connection settings; taxonomy sync; the five attributes; Call 1; Call 2; title/description generation; review screen with field gating; pricing; publish; local draft cleanup.
Later: prompt-management UI, U2Net, offline capture, OCR/ruler, batch create, number-drift check, Specialty cuts prose, primary-category correction UX.
## 16. Open / parked items
1. `attributes` element shape on `POST /products` is open — needs a live Whidbey product sample or the official Woo REST fields. Do not invent.
2. Server persistence approach is open — full OpenAPI slab CRUD vs a thinner FastAPI path.
3. `Specialty cuts` leaf prose is parked.
4. Primary-category correction and awareness is a UX problem, deferred.
5. Number-drift check is `later`.
6. Prompt management is post-M3.
7. The QUALITY/OPS extraction re-run is still pending (the first pass was truncated).
8. "Later docs prevail" is the rule, but the tag/archive still hold material not yet reconciled (e.g. U2Net, browser floor, TES vectors, deploy details).
## 17. Work items
1. ~~Re-run the QUALITY/OPS extraction.~~ Done 2026-09-18 (TEST-SPEC ~110 rows; plan/deploy/release ~120 rows).
2. Write `docs/REQUIREMENTS.md` namespace by namespace, starting with `CAPTURE`.
3. Draft the per-leaf title/prose work once the `METADATA` section is being written.
4. Migrate capability/contract docs into their homes, make docs branch-neutral, rebuild the structure check, wire CI.
## 18. Rulings deferred to a final cleanup pass
These surfaced during the QUALITY/OPS extraction. They do not block writing `REQUIREMENTS.md`; park them and reconcile in the cleanup pass.
1. Test directory layout: old TEST-SPEC mandates Vitest and `frontend/src/__tests__/`; shipped code uses the Node test runner (`node --import tsx --test`) and `frontend/tests/`. Contradiction.
2. Test coverage target (~95% for deterministic modules) — adopt or drop.
3. "The Test Bar" role and who authors reports versus Ty's sign-off.
4. `docs/checks/check-structure.sh` gate timing and criteria — now replaced by `tools/check_requirements.py`.
5. Deploy ports: proposal `18080/18443` versus UAT `:10881`, and `APP_HOSTNAME` binding.
6. Backup retention "7 daily + 4 weekly" has no verification test.
7. `SLAB_AES_KEY_OLD` rekey env placement (host vs compose).
8. Smoke step 5: local `published` versus Woo `draft` mismatch — intended or not.
9. Release process: `Build-release-standard` points at GitHub while the repo is Gitea.
10. Taxonomy sync endpoint path divergence across docs.
11. Ownership of `deploy/INVENTORY.md` across Gate B vs Phase 6.
12. Scope labels: do shipped/M3/later map to phases or to release milestones.
13. `C1`/`C2` (Call 1 / Call 2) namespace ownership ambiguity.
14. Whether `UAT-PRACTICE.md` change control is a gate.
15. Definition of "real fixtures" acceptance for TV-3, TV-6, TV-7, TV-10.
16. `INF-1` ownership: SETTINGS toggle versus QUALITY suite obligation.
17. Server-side API surface (`revision_conflict`, validation module, slab CRUD) belongs to the open server-persistence decision.
18. `output_px_min` "never below 1600" from old DEPLOYMENT/IMPL-PLAN versus shipped 800 floor.
@@ -0,0 +1,102 @@
# Session handoff — requirements reconciliation
- Date: 2026-09-18
- Branch: `docs/clean-main`
- HEAD: `84d7681`. The last pushed tip was `1603467`.
- Working tree: clean. This session's work is committed as `84d7681`; not pushed yet.
- This file supersedes the stale "Resume here" section 0 of
`2026-09-18-reconciliation-decisions.md`.
## Read first
1. `docs/STRUCTURE.md` — structure contract, ID namespaces, the step-5 ID stride rule.
2. `docs/REQUIREMENTS.md` — the PoR. 136 requirements.
3. `.audit/2026-09-18-migration-todos.md` — deferred source-doc edits for step 3.
4. `.audit/2026-09-18-coverage-gaps.md` — the serial gap worklist (GAP-1..GAP-7).
5. `.audit/coverage/README.md` — the coverage ledger schema.
## Gates
```
python tools/check_requirements.py -> PASS, 12 docs, 8 namespaces, 136 requirements
python tools/check_coverage.py -> PASS, 40 atoms, 12 gaps, 20/136 IDs claimed
python tools/check_coverage.py --strict -> FAIL by design until coverage is complete
```
## What this session did
1. Renumbered every requirement in steps of 5 per namespace (see STRUCTURE.md). Nothing
cites IDs yet, so this was free. First IDs: `CAPTURE-5`, `METADATA-5`, etc.
2. Applied owner corrections: `PUBLISH-8` (no image cap), `METADATA-16` (template is the
fallback only), `REVIEW-8` (calculated fields are not mutable), `PUBLISH-30`
(attempt-level failure wording), `PUBLISH-35` and `PUBLISH-36/37/38` (error triage).
3. Walked `CAPTURE.md`, `PHOTOS.md`, `CREATE.md`, `CONTENT-WOO.md` section by section.
Added five rows: `CAPTURE-41`, `CAPTURE-141`, `METADATA-66`, `PUBLISH-31`,
`SETTINGS-51`.
4. Built the coverage method: `tools/check_coverage.py`, `.audit/coverage/` (schema plus a
settings/auth/health pilot ledger), and the gap worklist.
## Rulings locked this session (do not relitigate)
1. `METADATA-1`, `-2`, `-3` stay as written.
2. Audit decisions beat older specs. Title separator is the hyphen ` - `.
3. Grade is exactly 1. `fig-*` tags are optional. The Figure attribute is at least 1.
Ready set is two images; `REVIEW-5` is the PoR.
4. Tag scope is important: sync keeps only the figure and feature tag families so non-wood
Woo metadata does not pollute the workflow (`SETTINGS-51`).
5. Content-generation logging stays (`METADATA-66`), it is the trace/debug/tuning record.
6. Partial-publish orphaned media: log it, surface a manual cleanup note, no auto-delete
(`PUBLISH-31`).
7. Order of the coverage walk: current docs, then tag docs, then the archived PRD, then the
Gitea main design issues (#1–#20). TEST-SPEC is done LAST, reconciled against a finished
PoR.
## Open work
1. Continue the coverage walk doc by doc, section by section. Remaining current docs:
`PRODUCT`, `README`, `UAT-PRACTICE`. Then the tag docs, the archived PRD, the main
issues, and finally TEST-SPEC.
2. The pilot ledger `coverage/settings-auth-health.md` mixes sources. When a walked source
collides with it, split the ledger into per-source files first (this write was started
and reverted once; get explicit approval).
3. Resolve the coverage gaps in one pass, then step 3 migration
(`docs/capabilities/`, `docs/contracts/`, branch-neutral, cite IDs), then retire the
working records.
## Known gaps
1. `.audit/2026-09-18-coverage-gaps.md` has GAP-1..GAP-7, all open. GAP-1 (`test-woo`
failure semantics) and GAP-2 (health/`woo_reachable`) are the ones with the most
downstream content.
2. The coverage ledger currently reports 12 `gap` atoms from the pilot slice.
3. Still-open decisions: the `attributes` element shape on `POST /products`, and server
persistence (full CRUD vs a thinner path).
4. Discussed but unresolved: Woo credentials are stored server-side, so two phones share one
credential row and a wrong password locks both out. A "last-known-good plus auth-gated
promotion" rule was proposed; no requirement row yet.
## Process rules
1. This is planning work. Walk in plan mode (read-only); flip to build only for edits the
owner has explicitly approved.
2. No file gets created, edited, or deleted without the owner saying go for that specific
change.
3. Where a doc and the shipped code disagree, the as-built code is what the PoR documents.
4. Raw evidence for any "done": gate output, diff, or command output.
## Environment
1. Subagents `general` and `explore` are routed to the local SWIFT model
(`deepblu5090-8084/Swift-Qwen3.8-27B-Q5_K_M.gguf`) in the global config
`~/.config/opencode/opencode.jsonc`. Config loads at startup; restart after edits.
2. SWIFT is suitable for mechanical extraction only (read and list). Dispositions and
rulings stay with the owner. It never writes.
3. `.audit/docs-structure-pass.tsv` is finished history from 2026-09-09. Leave it.
## Commit
- `84d7681` — coverage gate, migration TODOs, session handoff. Working tree clean.
- Touches: `docs/REQUIREMENTS.md` (+5 rows), `docs/README.md`, `AGENTS.md`,
`.audit/2026-09-18-reconciliation-decisions.md`, and the new `.audit` files plus
`tools/check_coverage.py`.
- Not pushed to origin as of this handoff.
+7
View File
@@ -0,0 +1,7 @@
ts phase decision why evidence result
2026-09-09T19:43:56Z harness ran check-structure.sh on untouched main tip capture red baseline before structure edits docs/checks/check-structure.sh FAILED as expected (red baseline)
2026-09-09T19:43:56Z frame done predicate is check-structure.sh exit 0 with lock phrases intact falsifiable gate for structure pass .audit/docs-structure-pass.tsv open
2026-09-09T19:45:25Z unit AGENTS ownership complete; Gates table removed; UX-DESIGN demoted; IMPL-PLAN owns gate meanings subtract calendar restatement and close ownership gap AGENTS.md,docs/UX-DESIGN.md,docs/IMPL-PLAN.md check-structure PASSED
2026-09-09T19:45:25Z unit TEST-SPEC and deploy docs label missing tree as Phase 0 targets stop agents inventing harness paths that are not on main docs/TEST-SPEC.md,docs/DEPLOYMENT.md,deploy/docker-compose.yml,README.md check-structure PASSED
2026-09-09T19:45:25Z verify ran docs/checks/check-structure.sh after all edits prove done predicate on real artifact docs/checks/check-structure.sh exit 0 VERIFIED
2026-09-09T19:47:17Z attention-fix restored Gate B meaning to original AGENTS wording; hardened check-structure for both deploy files and fuller math lock phrase Attention review flagged Gate B parenthetical as lock drift and weak deploy grep docs/IMPL-PLAN.md,docs/checks/check-structure.sh check-structure PASSED
1 ts phase decision why evidence result
2 2026-09-09T19:43:56Z harness ran check-structure.sh on untouched main tip capture red baseline before structure edits docs/checks/check-structure.sh FAILED as expected (red baseline)
3 2026-09-09T19:43:56Z frame done predicate is check-structure.sh exit 0 with lock phrases intact falsifiable gate for structure pass .audit/docs-structure-pass.tsv open
4 2026-09-09T19:45:25Z unit AGENTS ownership complete; Gates table removed; UX-DESIGN demoted; IMPL-PLAN owns gate meanings subtract calendar restatement and close ownership gap AGENTS.md,docs/UX-DESIGN.md,docs/IMPL-PLAN.md check-structure PASSED
5 2026-09-09T19:45:25Z unit TEST-SPEC and deploy docs label missing tree as Phase 0 targets stop agents inventing harness paths that are not on main docs/TEST-SPEC.md,docs/DEPLOYMENT.md,deploy/docker-compose.yml,README.md check-structure PASSED
6 2026-09-09T19:45:25Z verify ran docs/checks/check-structure.sh after all edits prove done predicate on real artifact docs/checks/check-structure.sh exit 0 VERIFIED
7 2026-09-09T19:47:17Z attention-fix restored Gate B meaning to original AGENTS wording; hardened check-structure for both deploy files and fuller math lock phrase Attention review flagged Gate B parenthetical as lock drift and weak deploy grep docs/IMPL-PLAN.md,docs/checks/check-structure.sh check-structure PASSED