101 lines
7.5 KiB
Markdown
101 lines
7.5 KiB
Markdown
# Milestone 1 — Plan of Record (POR)
|
||
|
||
Decisions captured as they are made. This is the working plan for implementing and UAT-ing Milestone 1. It is the source of truth for scope, order, and dispatch; the spec detail lives in `docs/CAPTURE.md` and `docs/PRODUCT.md`.
|
||
|
||
## Scope
|
||
|
||
Implement **Milestone 1 — Capture** only (see `AGENTS.md`). Browser-only, inference-free, no backend, no Woo create. Milestones 2–4 are out of scope.
|
||
|
||
## Method — TDD (non-negotiable)
|
||
|
||
Every card is delivered **test-first** per the `test-driven-development` skill:
|
||
|
||
```
|
||
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
|
||
```
|
||
|
||
- **Red-Green-Refactor**, tracer-bullet: one behavior slice at a time (RED→GREEN→REFACTOR), not all-tests-then-all-code.
|
||
- **Verify RED** (watch it fail for the right reason) and **Verify GREEN** (it passes + full suite stays green) are mandatory before the card is done.
|
||
- Code written before a failing test is **deleted and redone** — not kept as "reference."
|
||
- The deterministic core (math + PNG contract) is unit-tested in a browser-runnable JS suite; UI behaviors are tested with Playwright against the fixtures.
|
||
- A card is not complete until: every new function has a test, each test was seen failing first, the full suite passes with pristine output.
|
||
|
||
## Card breakdown (implementation order)
|
||
|
||
Each card follows TDD. "Define" = write the failing tests (RED); "Build" = minimal code to pass (GREEN); "Refactor" = clean up keeping green.
|
||
|
||
1. **Scaffold + Dockerfile + test harness** — SvelteKit project with the browser-only M1 runtime (Web Worker, canvas/OffscreenCanvas, IndexedDB via `idb-keyval`), `frontend/Dockerfile`, and the test harness (JS unit runner + **Playwright** web).
|
||
- *TDD note:* this card establishes the harness itself (a smoke test that runs and fails, then passes) so every later card has a place to be RED/GREEN.
|
||
2. **Deterministic core** — the pure math + PNG-encode functions.
|
||
- *RED:* unit tests for `scale`, `sqft`, `bdft`, width sampling, 1/8″ stepping, rounding, and the PNG contract (3:4, 8-bit RGBA, 80% fill, ≥1600px floor, undersized→retake). Run on the fixtures' calibration records.
|
||
- *GREEN/REFACTOR:* implement to pass; core is authoritative and server-less.
|
||
3. **Capture + Mask** — Add photo (JPEG; HEIC→"retake as JPEG" notice), green/black key, four knobs, debounced recompute, mask approve.
|
||
- *RED:* Playwright — load fixture, key sheet, approve; empty-mask blocks approve; HEIC shows the notice.
|
||
- *GREEN/REFACTOR:* build the Mask state to pass.
|
||
4. **Length axis** — min-area bounding rectangle + long-side axis, user rotate, approve.
|
||
- *RED:* Playwright — rect drawn from the approved mask, axis on long side, rotate, approve.
|
||
- *GREEN/REFACTOR:* build the axis state.
|
||
5. **Measure + PNG** — length/thickness (1/8″), compute sqft/bdft/widths, write the 3:4 inventory PNG. M1 stops here.
|
||
- *RED:* Playwright — enter L/thickness → Calculate; assert PNG is 3:4 with alpha, and numbers equal the fixture's expected values.
|
||
- *GREEN/REFACTOR:* build Measure + PNG encode.
|
||
6. **M1 UAT** — serve the container per `deploy/README.md` §Milestone 1 UAT; run the full Playwright suite in the container; then the manual phone pass. Record host + URL in `deploy/INVENTORY.md`.
|
||
|
||
## Deployment (UAT)
|
||
|
||
See `deploy/README.md` §Milestone 1 UAT — deployment POR: one container, host chosen at runtime, LAN-reachable URL, no backend.
|
||
|
||
## Dev / QA worker dispatch
|
||
|
||
Two local inference endpoints are available as dispatchable workers for test / dev / QA:
|
||
|
||
- **`.202:8081`** — `gemma-4-12B-it-q4_k_m` (12B, Q4) — **completion only, no vision.** Use for lighter text: drafting, code review, summaries.
|
||
- **`.202:8082`** — `Qwen3.8-27B-UD-IQ3_XXS` (27B, IQ3) — **completion + multimodal (vision).** The **vision worker** (any task that must look at a slab photo) and the stronger general-reasoning endpoint.
|
||
|
||
Coordinator: Hermes (me) — plans, decomposes, dispatches, verifies, and does work directly when a card is small or judgment-heavy.
|
||
|
||
### Calibrated delegation policy (2026-09-14)
|
||
|
||
- **Frame every prompt**: system role + "show each step" + explicit constraints. Small/low-quant models drop multi-step arithmetic in one-shot "reply JSON only" prompts but get it exactly right with scratch-space framing. Do not judge capability from under-framed probes.
|
||
- **The deterministic core stays the coordinator's** (TDD'd, unit-tested). A model that's "usually right" on math is not good enough for the spec — math is cheap to test and must be exact.
|
||
- **Verify before land**: any load-bearing model output is checked against tests/spec before entering the repo. Workers are assist, not autonomous builders.
|
||
- **Output quirks**: gemma wraps JSON in ``` fences — strip before parsing. Vision calls run ~18s/image (text ~1s).
|
||
- **One task per endpoint at a time** (no parallel on the same endpoint — backs up and overheats).
|
||
- Both run low-quant (Q4/IQ3). Fine for framed assist; deep sustained reasoning is best done by the coordinator directly.
|
||
|
||
## Test plan (M1)
|
||
|
||
Three layers. The deterministic core is unit-tested; the end-to-end path is Playwright; a real phone is the final UAT gate.
|
||
|
||
### 1. Unit (deterministic core) — must pass before any UI consumes it
|
||
- `bdft = sqft × thickness_in`; `sqft = (mask_px / scale²) / 144`; `scale = longest_axis_px / L`.
|
||
- 1/8 in stepping; rounding (sqft/bdft 2 decimals).
|
||
- Width sampling every 6 in along the approved axis.
|
||
- PNG encode contract: 3:4 aspect, 8-bit RGBA, 80% fill, shorter side ≥ 1600px when source allows; undersized source → warn + retake (no upscale).
|
||
- Mask empty → approve blocked.
|
||
|
||
### 2. Playwright (automated end-to-end, runs in the UAT container's browser)
|
||
Walks the 5 states against a **sample photo**:
|
||
- Add photo → Mask (set sheet + sensitivity) → approve → Length axis → approve → Measure (enter L, thickness) → Calculate.
|
||
- Assert: PNG rendered, dimensions = 3:4, alpha present; sqft/bdft/widths equal the expected values for that fixture (within tolerance); numbers visible on screen.
|
||
- HEIC input → "retake as JPEG" notice shown (not a crash).
|
||
- Device draft: reload → Resume → Continue restores last approved state.
|
||
|
||
### 3. Manual phone UAT (final gate)
|
||
On a real phone (iOS Safari / Android Chrome) over the LAN UAT URL: repeat the happy path with one real slab; confirm PNG + numbers on screen. Record host + URL in `deploy/INVENTORY.md`.
|
||
|
||
## Test fixtures (sample pics)
|
||
|
||
Real slab photos are the fixtures (supplied by Ty from `\\truenas.local\Business\Samples`, SMB user `SMBSVC`). Each is a DJI MIMO top-down JPEG, ~4000×2256, slab on a green/black sheet.
|
||
|
||
`tests/fixtures/`:
|
||
- **sample_01 … sample_0N.JPG** — a representative handful of real slab photos (pulled on demand from the TrueNAS Samples share; do not bulk-copy the whole folder).
|
||
- Each fixture gets a **calibration record** in `tests/fixtures/<name>.json`: the slab's true length and thickness (in inches), the sheet color, and the approved mask/axis reference — used to compute the expected `scale`, `sqft`, `bdft`, and sampled widths for assertions.
|
||
|
||
The real photos drive both **bg removal** (green/black key) and **rectangle/axis calibration**. Expected values come from the calibration records, so assertions stay deterministic even on real imagery.
|
||
|
||
**M1 fixture set (agreed, complete for M1):** three black-sheet slabs — one irregular (stress-tests the min-area rectangle/axis), two clean elongated. Green-sheet keying is deferred (not an M1 fixture). A 1 HEIC sample (optional) for the decode-fallback test.
|
||
|
||
## Open decisions
|
||
|
||
- (none outstanding for M1 as of this plan; new decisions append here)
|