- shared/ ports the worksheet's ledger math, time parsing, and reference tables (cultivars/processes/roast-levels/machine bands) as browser-safe ESM, imported by both the server and the browser so the arithmetic can't drift between them. - server/prefill.js runs a zero-tool Pi Coding Agent SDK turn to extract page facts from a bean product URL, then derives worksheet field IDs deterministically from reference-data.js — the model never invents a first-crack anchor or a modifier. - server/alog.js ports the Python alog_parser.py's format handling, including the tokenizer-based Python-dict-literal-to-JSON conversion the real files need. - public/ is the worksheet reproduced as a live HTML form: worksheet.css is a verbatim copy of the paper worksheet's print CSS, print.js bakes values into the print layout so the same DOM renders both on screen and on paper. - Ledger math verified against both of the paper worksheet's worked examples; alog parser verified against all 14 real logs in ref/roasts/. Co-Authored-By: Claude Sonnet 5 <[email protected]>
56 lines
3.1 KiB
Markdown
56 lines
3.1 KiB
Markdown
# Roast Planner Webapp
|
|
|
|
A fillable, live-computing web version of the manual coffee roast plan worksheet
|
|
(`hope_roaster/roast-planner/manual-roast-planner.html`), plus:
|
|
|
|
- **Prefill from a bean URL** — paste a roaster's product page URL; the server fetches it and
|
|
uses the Pi Coding Agent SDK (zero-tool, one-turn extraction) to pull out whatever it can
|
|
find (cultivar, origin, processing, roast level), then deterministically maps that to
|
|
worksheet field IDs using the same reference tables as the paper worksheet. It never
|
|
invents a first-crack anchor or a modifier — those only ever come from the reference
|
|
tables, keyed off what the page actually states.
|
|
- **Reference curve from an Artisan `.alog`** — upload a real roast log (or browse a local
|
|
library directory) to overlay its actual milestones/curve on the same SVG grid as your
|
|
plan, dashed and in a different color.
|
|
- **Live ledger** — the worksheet's time-ledger math (first crack, yellow, Maillard,
|
|
development, drop, and the four sanity-check ratios) recomputes as you type, using the
|
|
exact same arithmetic as the paper worksheet (verified against both its worked examples).
|
|
- **Print** — bakes typed values into the print layout and reuses the paper worksheet's
|
|
print CSS, so `File > Print` produces the same 2-page front/back sheet.
|
|
|
|
## Run it
|
|
|
|
```bash
|
|
npm install
|
|
npm start # http://localhost:8090 (set PORT to override)
|
|
```
|
|
|
|
Prefill requires a model configured via the `pi` CLI (`~/.pi/agent/{models,auth}.json`) —
|
|
without one, `/api/prefill` returns `503 no_model` rather than crashing. Everything else
|
|
(the form, ledger, curve, `.alog` upload) works with no model configured.
|
|
|
|
## Layout
|
|
|
|
- `shared/` — browser-safe ESM modules imported by *both* the Node server and the browser
|
|
(served statically at `/shared/`). This is the single source of truth for the ledger math,
|
|
time parsing, and reference data tables — never duplicate this logic in `server/` or `public/js/`.
|
|
- `server/` — Express routes: `/api/prefill`, `/api/alog`, `/api/alog/library[/:filename]`.
|
|
- `public/` — the static frontend: `index.html` (the worksheet as a form), `worksheet.css`
|
|
(a verbatim copy of the paper worksheet's print CSS — port changes from there, don't
|
|
hand-edit divergently), `app.css` (screen-only chrome + form-control styling), `js/`.
|
|
|
|
## Where the reference numbers come from
|
|
|
|
`shared/reference-data.js` is ported from
|
|
`/Users/shane/dev/hope_roaster/roast-planner/manual-roast-planner.html`'s Step 1 (cultivars),
|
|
Step 3 (processing), Step 4 (roast levels), Step 8 (machine bands), and Step 7 (sanity bands).
|
|
If those tables change in the paper worksheet, port the change here too.
|
|
|
|
## Known gaps (v1)
|
|
|
|
- No automated test suite yet (the ledger math and `.alog` parser were verified manually
|
|
against the worksheet's worked examples and all 14 logs in `ref/roasts/`, respectively).
|
|
- Roastetta (roastetta.com) integration is intentionally out of scope — it needs a headed,
|
|
Cloudflare-clearing browser and the operator's own credentials. Use the `.alog` file picker,
|
|
or point `ALOG_DIR` at wherever the `roastetta` skill already downloaded files.
|