20 Commits
Author SHA1 Message Date
snowspeederandClaude Fable 5 385474ecef Removable reference curves, audit fixes across pages, shaded Academy art
Test and deploy / test-and-deploy (push) Successful in 1m8s
The planner's Artisan .alog drawer now shows what's attached with a
"Remove reference curve" control (re-rendered per drawer open), so adding
a reference curve is no longer a one-way door; /api/alog shares the 8 MB
body cap so real-sized logs parse instead of failing with "bad_request".

Deep-evaluation fixes: editing a brew of an archived bean no longer
silently detaches the bean; the roasts pending-review poll no longer
wipes in-progress after-roast edits; roasters gain an Edit (rename/model)
action; the gear page refuses to autosave over a failed load; duplicating
a plan carries its custom name; cupping sessions can attach a plan after
creation (ownership-checked PUT + selector); admin user deletion also
refreshes plans/audit; cupping cup-count subtitle stays live; roasts
error-row colspan corrected. Regression tests cover the new cupping PUT
and the /api/alog body cap.

Academy scenes drop the flat paper-cutout look: shared defs provide
radial-gradient shading on every bean/half-bean/particle, flame gradients
with radiant halos, soft ground shadows, and a warm-lit stage background;
fill-shift animations now ride a partial-opacity tint overlay so shading
survives the color change.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-11 16:59:28 -04:00
Shane MaynardandClaude Fable 5 8b80c3fa6f Academy v4: 3 research-backed lessons (30 slides + audio); new bean logo; custom plan/lot names
Test and deploy / test-and-deploy (push) Successful in 59s
Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-09 14:30:42 -04:00
Shane MaynardandClaude Fable 5 64c1b3605b Add the Academy: narrated, animated roasting & brewing lessons; cupping link on roast detail
Test and deploy / test-and-deploy (push) Successful in 53s
Academy (/academy, 'Learn' nav group):
- 10 lessons / 45 slides across two tracks. Roasting: seed anatomy and
  composition, drying & the turning point, Maillard, first crack &
  development (DTR), curve/RoR reading (crash, flick, stall), defects →
  one-change discipline. Brewing: extraction physics (dissolving order,
  yield, grind, temp/time/ratio), then technique per brewer family —
  immersion (French press, AeroPress, Clever/Hario Switch, cold brew,
  cupping), percolation (bloom, V60, Chemex/Kalita, batch, percolator),
  espresso & pressure (puck prep, shot reading, dialing in, moka)
- One cohesive scene system: 25 parameterized animated SVG scenes drawn
  from the app's palette (beans, curves, phase bars, brewers reusing the
  silhouette library), CSS keyframe animations, reduced-motion support
- Narration: Azure TTS (en-US-Andrew HD, eastus) pre-generated to 45
  committed MP3s by scripts/generate-academy-audio.mjs; slides speak
  phonetic respellings (my-YARD, KEM-ex, MOH-kah…) while captions show
  normal spelling; hands-free autoplay advances after each clip
- Player: slide dots, keyboard arrows/space, per-slide captions

Roast detail: 'Open cupping session' button next to cup notes (opens or
creates the linked plan's session) — its score and flavors flow into
the updated .alog download.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-09 09:04:39 -04:00
Shane MaynardandClaude Fable 5 c6c392730f Fix desktop header overflow; add plan attachment on roast detail
Test and deploy / test-and-deploy (push) Successful in 55s
- The app header now wraps: brand + actions on the first row (actions
  shrink and wrap instead of pushing Print off-screen), section pills
  always on their own full-width row; the planner's sticky offsets use
  a two-row --header-h via body:has(#plan-form)
- Roast detail gains a Plan selector (attach/detach any of your plans)
  alongside the Machine selector; PUT /api/roasts/:id accepts
  roastPlanId with ownership checks

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-09 08:47:13 -04:00
Shane MaynardandClaude Fable 5 4a3d192c2c Move After-the-Roast onto actual roasts; add Artisan-importable updated .alog download
Test and deploy / test-and-deploy (push) Successful in 56s
One system: post-roast observations (weights, colour, DTR, cup notes,
'one change next batch', disproof) now live on the uploaded roast
(actual_roasts.after, migration 011), edited on the roast detail view
with weights/DTR prefilled from the .alog itself. The planner's screen
section is removed (the print worksheet keeps its hand-fill copy), and
the lot 'last refine' suggestion reads the note from both the new home
and legacy plans, newest wins.

Every roast now downloads two ways: the untouched original .alog, and
an updated supplemental copy with the app's data written back as valid
Artisan fields (weight, beans, roastingnotes incl. the LLM review,
cuppingnotes incl. linked cupping score/flavors) — serialized as a
Python literal so Artisan's ast.literal_eval re-imports it.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-09 08:35:11 -04:00
Shane MaynardandClaude Fable 5 a341d67467 Add roaster (machine) management, mobile header-tools redesign, and profile pictures
Test and deploy / test-and-deploy (push) Successful in 1m0s
Machines:
- roasters table + actual_roasts.roaster_id (migrations 009): per-user
  machines with a default; uploads attach to the default roaster and are
  reassignable from the roast detail view
- Learning is now per machine: /api/roaster-profile scopes to a roaster
  (default when unspecified) and applies the user's override tweaks
  (milestone temps, TP time, pace factor) on top of learned medians
- /roasters page: machine list + analysis report showing learned vs
  applied values with editable tweaks, typical RoR, and a plain-language
  list of the adjustments applied to plans; planner honors a manual pace
  override; evaluations use the roast's own machine profile

Mobile header redesign:
- The planner's header tools collapse behind a single 'Tools ▾'
  disclosure (dropdown card) at ≤720px, keeping the fixed three-row
  mobile header with no wrapped or scrolling button rows; desktop
  renders inline via display:contents (same DOM, same handlers)

Profile pictures:
- users.avatar (migration 010) + PUT/GET/DELETE /api/account/avatar;
  client-side centre-crop resize to 128px JPEG; avatar shows in the nav
  chip on every page; included in full backups

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-09 08:17:10 -04:00
Shane MaynardandClaude Fable 5 e62b9601a2 Add Equipment page: owned brewers and grinders filter the Brews UI
Test and deploy / test-and-deploy (push) Successful in 59s
- user_gear table (migration 008) + GET/PUT /api/gear (brewer keys
  validated against the taxonomy, grinders deduped/trimmed)
- /gear page: silhouette multi-select for owned brewers (autosaves) and
  a grinder list; nav gains Brewing → Equipment
- Brews page: with gear configured, the picker shows only owned brewers
  (plus the edited brew's method) with a show-all toggle; grinder field
  suggests your grinders; empty-gear state links to /gear
- Included in full backups, per-user export, and the OpenAPI spec

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-09 08:08:32 -04:00
Shane MaynardandClaude Fable 5 c130efb180 Prefill: classify unknown cultivars into a reference group so the ledger still computes
Test and deploy / test-and-deploy (push) Successful in 59s
The extraction schema gains cultivarGroup (typica/bourbon/ethiopian/
hybrid, classified by the LLM from coffee genetics); when the named
variety isn't in the cultivar table, deriveFields now falls back to the
group's first-crack anchor (number still comes only from the reference
table) instead of leaving 1.4 blank and breaking every downstream
calculation. deriveFields exported + unit-tested.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-09 08:03:46 -04:00
Shane MaynardandClaude Fable 5 f781930832 Add a Recipe/steps field to brew logging
Test and deploy / test-and-deploy (push) Successful in 1m16s
Free-text recipe (bloom, pours, timings) distinct from tasting notes and
next-time notes: new brews.recipe column (migration 007), form textarea,
shown under the recipe summary in brew history, carried by Brew again,
included in backups and the OpenAPI spec.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-09 08:02:06 -04:00
Shane MaynardandClaude Fable 5 38c7d01e03 Add brewing section, plan chat, roaster learning, API tokens, Swagger docs, and full backup
Test and deploy / test-and-deploy (push) Successful in 1m6s
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]>
2026-08-08 22:37:42 -04:00
Shane MaynardandClaude Fable 5 5efaeb63c9 Add admin LLM model setting; rename Pi to LLM in the UI; drop table Review column
Test and deploy / test-and-deploy (push) Successful in 49s
- New server/llm.js consolidates ModelRuntime + model selection: admin
  setting (app_settings.llm_model) > LLM_MODEL/PREFILL_MODEL env > first
  available; used by both prefill and roast evaluation
- GET/PUT /api/admin/llm lists configured models and stores the choice
  (validated against the list; empty = auto; audited); admin page gains
  an LLM section with a model picker
- All user-facing 'Pi agent' wording is now 'LLM'; no_model error message
  no longer references the pi CLI
- /roasts table: Review column removed (review lives in the detail view)

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-08 22:12:42 -04:00
Shane MaynardandClaude Fable 5 eb82263ead Add finished-roast .alog uploads with Pi agent deep review and /roasts history
Test and deploy / test-and-deploy (push) Successful in 1m39s
- POST /api/roasts stores the original .alog verbatim (multiple per plan),
  parses it server-side, and kicks off an async zero-tool Pi agent review
  (grade, highlights, concerns, next-batch suggestions, plan-vs-actual)
- /roasts page: table of historical actual roasts with review summaries;
  row detail renders the BT curve as SVG with the plan curve overlaid,
  shows the full review, and offers original-.alog backup download,
  re-evaluate, and delete
- Planner's Reference curve drawer gains a multi-file finished-roast
  uploader that attaches to the open (synced) plan
- Failed reviews record the error on the row and are retryable via
  POST /api/roasts/:id/evaluate (e.g. once a model is configured)

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-08-08 20:18:22 -04:00
snowspeederandClaude Sonnet 5 2237c199c1 Add per-user learned machine profile; fix methodology honesty issues
Test and deploy / test-and-deploy (push) Successful in 1m26s
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]>
2026-07-31 12:40:03 -04:00
snowspeeder 59645e59b5 Add green-bean inventory and cupping features
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.
2026-07-30 14:47:15 -04:00
snowspeeder 9f0a3dbc74 Fallback to Browserless for rate-limited prefills 2026-07-30 08:16:22 -04:00
snowspeeder 122427d30d fix: redirect authenticated users to planner 2026-07-29 22:56:06 -04:00
snowspeeder 22e6e721a7 chore: format auth code and update runtime 2026-07-29 22:11:08 -04:00
snowspeeder 892479dceb feat: harden authenticated deployment 2026-07-29 22:04:40 -04:00
snowspeeder 432dd2176f feat: add secure auth, admin and postgres persistence 2026-07-29 21:52:22 -04:00
snowspeederandClaude Sonnet 5 fedaf29847 Initial roast planner webapp: fillable worksheet, live ledger, curve, URL prefill, .alog reference curve
- 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]>
2026-07-29 15:41:35 -04:00