You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Calibrate every head, unify the chip language, fix the modal layout (#269)
* feat: calibrate every head, unify the chip language, fix the modal layout
Closes#265, #266, #267, #268.
CALIBRATION EVERYWHERE (#265). Taste and Tox21 still ran on a flat 0.5 with only AUROC shown —
the exact reporting gap #261 closed for aroma and mouthfeel. Both now use the same out-of-fold
calibration with a 50% precision floor, and /api/heads publishes threshold, precision, recall and
confident_capable for all four modalities.
The taste heads were mildly shy, as expected with hundreds of positives each (sweet 0.33, umami
0.33, bitter 0.51), and all six clear the floor at 0.50-0.87. The Tox21 result is the one that
matters: every one of the twelve calibrated UPWARD — NR-AR to 0.69, NR-AR-LBD 0.65, NR-ER 0.63 —
which means a flat 0.5 had them OVER-flagging. That is the opposite direction from the thin aroma
heads and the more dangerous one, because a caution flag that cries wolf teaches people to ignore
the flags that matter.
CHIP LANGUAGE (#266). Flavor, note, taste and mouthfeel chips had each been given a different
border STYLE at a different time — dashed, dotted, thicker, plus per-taste text recolouring — so
they read as four accidents rather than one system. They now share a pill, a size and a border
weight, and carry identity in a leading dot in the family's own hue. Each studio section also
gained a plain-language paragraph on what that dimension IS and why it matters: a flavor is the
whole percept, a note is what the nose reads, taste is the basics the tongue reads, mouthfeel is
touch reported by the trigeminal nerve. Menthol is cold without a temperature change; that
distinction is load-bearing and nothing in the UI had ever said it.
ALL MODALITIES ON CARDS (#267). Substitute and neighbor cards showed taste and aroma but not
mouthfeel. Read straight off the profile matrix, whose mouthfeel columns were already there, so
it costs no extra inference — and each sensation must clear its own calibrated threshold, so a
card never shows something the modal would call indicative.
MODAL LAYOUT (#268). Two real bugs, both measured rather than guessed:
- Mobile: the swap grid used `1fr`, which is minmax(auto,1fr), and `auto` will not shrink below
min-content — so the substitutes and neighbors cards rendered 468px wide inside a 358px modal.
minmax(0,1fr) fixes it; .modal-top already had this and .swap-grid did not.
- Desktop: #results is a flex column whose 14px gap separates the cards, but the render path set
an inline display:block on it, and block boxes ignore `gap`. The Heads card had been sitting
flush against the Substitutes card below it. Clearing the inline style lets the stylesheet win.
Verified with a Playwright probe at 390px and 1440px: no card overflows its container at either
size, and no two cards are within 8px of each other on desktop.
Signed-off-by: Austin L. <86896075+rvnminers-A-and-N@users.noreply.github.com>
* docs: define AUROC, threshold and precision where people actually land
HOW-IT-WORKS.md used CV-AUROC eleven times and never said what it is beyond a parenthetical, and
never mentioned threshold, precision or recall at all — the real explanation lived only in
ACCURACY.md, one click further than most readers go. A six-term glossary now sits at section 0.5,
before any number is used: head, AUROC (0.5 is a coin flip, 1.0 is never wrong), threshold (not a
flat 0.5 — 0.16 to 0.85, fitted per head), precision (when it says yes, how often is it right),
recall, out-of-fold, and confident vs indicative. Two sentences each.
The same glossary, compressed to a definition list, is now a card in the site's own How-it-works
grid, so it reaches someone who will never open the docs folder.
Also tightens the taste wording, which was loose in both places: there are FIVE basic tastes and
SIX taste heads. `tasteless` is a head that predicts the documented absence of taste — genuinely
useful, since it is how you find a clean carrier — but it is not a sixth basic taste, and calling
it one is the kind of small inaccuracy a flavorist would notice immediately.
Signed-off-by: Austin L. <86896075+rvnminers-A-and-N@users.noreply.github.com>
* docs(arch): pin the frontend UI kit and record what we deliberately excluded
Three stack questions kept resurfacing, so they are now answered in the one place someone would
look, with the reasoning rather than just the verdict.
Frontend is pinned to React 19 + Vite + TypeScript with Tailwind and shadcn/ui, explicitly NOT
MUI. shadcn is copy-in rather than import, so the components land in our own source tree where
they can be read and owned — which for a portfolio is the difference between showing you used a
component library and showing you can build one. Flavormancer also already has a visual identity
(the purple/teal gradient, the gilded scroll rods, the flask loader) that Material would flatten,
and the port would be spent overriding it. The trade is stated honestly: MUI wins when you need an
enterprise data-grid and date pickers tomorrow. This app is cards, chips, charts and a modal.
Node.js is scoped to build tooling and an optional TypeScript MCP server beside the Python one —
never a third backend. Two API stacks is breadth; three is sprawl, and it reads as indecision.
Laravel is deliberately absent and the reasoning is written down so nobody re-opens it: it is a
good fit for CRUD-and-content products and is used heavily elsewhere in this portfolio, but
Flavormancer is on-prem scientific computing. Adding a familiar framework that proves nothing new
would blur that. Choosing against your most comfortable stack when it does not fit is the point.
Signed-off-by: Austin L. <86896075+rvnminers-A-and-N@users.noreply.github.com>
---------
Signed-off-by: Austin L. <86896075+rvnminers-A-and-N@users.noreply.github.com>
Copy file name to clipboardExpand all lines: docs/ARCHITECTURE.md
+20-1Lines changed: 20 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,12 +30,31 @@ costs nothing on Track A — the demo keeps working while the product is built.
30
30
| App / API |**ASP.NET Core (C#)**| Enterprise default for a service like this: strong tooling, broad hiring pool, first-class ONNX Runtime support. |
31
31
| ML serving |**ONNX Runtime in-process in .NET**| Taste models (sklearn → `skl2onnx`) run inside the .NET app, no Python at runtime. |
32
32
| Aroma serving |**Python FastAPI sidecar***(only if needed)*| The GNN may not export to ONNX cleanly; if not, a thin localhost sidecar does aroma inference only. Best case it exports and there's zero Python at runtime. |
33
-
| Frontend |**React**| Deepest hiring pool and the lightest fit for a simple single-screen workbench. |
33
+
| Frontend |**React 19 + Vite + TypeScript**| Deepest hiring pool and the lightest fit for a simple single-screen workbench. |
34
+
| UI kit |**Tailwind + shadcn/ui***(not MUI)*| shadcn is copy-in, not import: the components live in our source tree where they can be read and owned. MUI would flatten Flavormancer's existing visual identity into Material and we would spend the port fighting it. The trade is real — MUI wins if you need an enterprise data-grid and date pickers tomorrow; this app is cards, chips, charts and a modal, which is shadcn's sweet spot. |
34
35
| Database |**PostgreSQL + pgvector**| Mature and battle-tested; pgvector backs the substitution-search index with first-class vector search. |
35
36
| Deploy |**Linux + Docker Compose** on the client-owned box | Single-box, small user count → Compose, not Kubernetes. Containers make the OS matrix irrelevant. |
36
37
37
38
---
38
39
40
+
## Deliberate exclusions
41
+
42
+
What we chose **not** to use matters as much as the stack, and both of these come up often enough
43
+
to be worth writing down.
44
+
45
+
**Node.js — build tooling and MCP only, never a third backend.** Two API stacks (the shipping
46
+
Python/FastAPI service and the planned .NET one) is breadth; a third is sprawl, and it reads as
47
+
indecision rather than range. Node earns its place in exactly two spots: the React toolchain
48
+
(Vite, TypeScript, the test runner), and — optionally — a **TypeScript MCP server** alongside the
49
+
Python one, which is ~200 lines and demonstrates the official TS SDK against the same contract.
50
+
51
+
**Laravel — deliberately absent.** It is a genuinely good fit for CRUD-and-content products and is
52
+
used heavily elsewhere in this portfolio. It is the wrong tool here: Flavormancer is on-prem
53
+
scientific computing, and adding a comfortable framework that proves nothing new would muddy that
54
+
story. Choosing against your most familiar stack when it does not fit is the point.
55
+
56
+
---
57
+
39
58
## The core principle: Python trains, .NET ships
40
59
41
60
Training language is an *internal build detail*, not part of the product. Nobody
0 commit comments