Brewing:
- roasted_beans + brews tables; /beans (bean management with LLM URL
prefill) and /brews (silhouette brewer picker across immersion/
percolation/espresso, recipe fields, auto ratio, 0-10 rating, tasting
notes); bean remaining weight derived from logged brew doses
- Green inventory lot form also prefills from a product URL
Navigation/UX:
- Side nav is now generated from one definition in nav.js, grouped
Roasting / Brewing / account, consistent on every page
LLM:
- 'Ask the LLM' chat drawer on the planner (stateless /api/plan-chat)
grounded in the plan, computed ledger, learned pace, and a new
roaster-behavior profile aggregated from uploaded .alogs
(/api/roaster-profile: TP lag, phase RoR, median milestone temps)
- The profile also feeds roast reviews and the planner curve's fallback
milestone temps
API platform:
- User-generated bearer tokens (rpt_…) with account-page management;
token requests skip CSRF; hand-authored OpenAPI 3 spec at
/api/openapi.json rendered by self-hosted Swagger UI at /api-docs
- Full-database backup export/import (admin) + per-user data export
Co-Authored-By: Claude Fable 5 <[email protected]>
Replaces the flat additive batch-size correction with a per-user
multiplicative pace factor learned from each account's own logged
roasts (shared/learn.js, GET /api/machine-profile), plus a lot-scoped
"last refine" auto-suggestion. Also fixes the reference data being
framed as "your own roasts" on a now-multi-user product, and
reclassifies the drying/Maillard sanity checks as informational since
they're algebraically derived from the DTR check rather than
independent (yellow = 0.56 x first crack, not entered separately).
Bug fixes found by an adversarial Opus review of the first pass:
- Unicode minus sign (U+2212) broke duration parsing against the
app's own generated refine-suggestion text
- Printed sanity-checks table still showed a bare pass/fail glyph for
the now-informational drying/Maillard rows
- Printed time-ledger box didn't show the pace multiplication step,
so it stopped reconciling by hand once pace != 1
- Field 6.4 (manual batch correction) was double-counted: excluded
from the learned-pace fit but added back after the multiplication
- Learned pace had no outlier rejection or hard clamp
- computeLedger had no test coverage
- Batch-size help copy overstated what the pace factor models (it's
a single blanket ratio, not conditioned on batch weight)
A follow-up Opus pass also caught the per-user profile cache
surviving logout/account-switch in a shared browser; fixed by
sweeping it alongside the existing plan-draft cleanup.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Highest severity: injected "?" buttons were hijacking the implicit
<label> association on 14 fields, so clicking the label text opened
the help dialog instead of focusing the input and screen readers lost
the input's accessible name. ensureLabelAssociation() now gives each
affected input an explicit id/for pairing before the button lands.
Also: milestones-ror/actuators topic placement is now text-matched
with a warning fallback instead of blind array indexing; every topic
warns if it resolves zero containers; dialog temperatures (milestone
table, RoR budget, worked example, both charge-setting tables) now
respect the °C/°F toggle instead of being stuck in °C; the print
worksheet's duplicate curve chart was missing the data-tempc
attributes its live counterpart had, so only its title/caption (not
its axis numbers) converted; the "?" trigger's touch target grew from
15px to a WCAG-conformant ~25px without changing the visual dot; two
genuine coverage gaps closed (a roast-log checklist topic, a
curve-reading topic); a worked feasibility example was restored; two
claims that didn't trace back to the source worksheet were corrected
(an invented "±15 seconds" sweet-spot tolerance, a wrong
moisture-to-time mapping); three cultivar cells regained detail lost
in the original transcription; a data-transcription footnote no
longer leaks into an unrelated topic; checklist items keep their list
semantics under VoiceOver.
Co-Authored-By: Fable <[email protected]>
Co-Authored-By: Opus <[email protected]>
Adds a help-dialog UI (field-help.js/field-help-content.js) surfacing
per-field guidance, expands cultivar and process reference data with
cup notes, sweet-spot width, and watch-fors, and adds a Makefile for
common npm tasks.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Ports inventory management and SCA-style cupping scoring from
hope_roaster: lot tracking with audit-logged consumption, cupping
sessions with server-authoritative scoring and a live radar chart,
and links from the planner (draw-from-lot, open-cupping-session).
Also fixes the Blend/Single-origin toggle layout, replaces tooltips
with an in-context "why" teaching layer, and stages the planner UI
into pre-roast vs. post-roast phases.
- 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]>