Add per-user learned machine profile; fix methodology honesty issues
Test and deploy / test-and-deploy (push) Successful in 1m26s
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]>
This commit is contained in:
+6
-1
@@ -1,11 +1,16 @@
|
||||
// Browser-safe. No node:* imports, no DOM. Imported by both server and browser.
|
||||
|
||||
const DASHES = /[‒–—−-]/; // -, –, —, minus sign
|
||||
// Matches only the non-ASCII members of DASHES — used to fold a leading minus/en/em dash down to
|
||||
// an ASCII hyphen before sign detection, so a string like "−0:30" (U+2212, the character every
|
||||
// signed number in this app's own reference data — SYMPTOM_FIXES, cultivar profiles — is written
|
||||
// with) parses instead of silently returning null.
|
||||
const NON_ASCII_DASHES = /[‒–—−]/g;
|
||||
|
||||
/** "8:45" -> 525, "-0:20" -> -20, "+0:15" -> 15, "0" -> 0, "90" -> 90 (bare seconds). null on junk. */
|
||||
export function parseDuration(str) {
|
||||
if (str === null || str === undefined) return null;
|
||||
const s = String(str).trim();
|
||||
const s = String(str).trim().replace(NON_ASCII_DASHES, "-");
|
||||
if (s === "") return null;
|
||||
const sign = s.startsWith("-") ? -1 : 1;
|
||||
const body = s.replace(/^[+-]/, "");
|
||||
|
||||
Reference in New Issue
Block a user