Plain-English record of the v2 program. One entry per meaningful step: what got finished · what's next · anything needed from Shad.
Shad chose PRIVATE distribution (not a GitHub Release). Artifact built + scanned clean.
- Artifact:
release/Cut Protocol Setup 1.0.0.exe(209,270,871 B / ~200 MB). SHA-256996877c639fcc29adced66c18e6b3914e5811f4021e6c53058dac726590a1ef3. - Stage 3 scan: all PASS — no secrets, no personal data, 0 npm-audit vulns,
brain-purity/supply-chain green. Report:
security/scan-report.md. Bundle carries ONLY the cleandev.db.template+ app (no.env, nodev.db, no backups). - Stage 2: data-safety block verified (
docs/release/fresh-install-check.md); interactive install-flow rows PENDING (best run on a clean profile). - NO
gh releasecreated (private choice). Hand-off: Shad launches the .exe once to confirm it opens, runs it through virustotal.com, then uploads to Google Drive and shares only to the tester's Gmail. Email draft provided.
The installer no longer ships secrets or personal data — the M4 fix.
- Clean template DB:
backend/scripts/buildTemplateDb.mjscopies dev.db and deletes all 22 personal tables (fails if a new table is unclassified), keeping the library (864 foods, 889 recipes + taste tiers). 0 users/profiles. - Per-install JWT:
electron/main.cjsnow generates a session secret on first run into userData (never bundled) instead of reading the owner's real.env. API keys simply absent in a shared build → brain off, app works fully offline. - Config: extraResources ships only the clean
dev.db.template(no.env); build.files strips dev.db/backups/scripts/docs/audit/release/.agent. - Blocking gate:
scripts/distPrecheck.mjswired aspredist— fails the build if the template has personal rows/emails, if the config would ship the real .env/dev.db, or if a secret sits in shipping code. PASSES clean.checkDistSafenow takes a file arg + a tightened email regex (no cuid byte-noise FP).
Next (Doc 2): Stage 2 fresh-install checklist · Stage 3 artifact scan report · Stage 4 build + SHA-256 + GATE (stop for Shad's go) + GitHub Release link.
Built the three deferred parts, each committed + verified (tests green, golden BRAIN=off byte-identical, brain-purity clean):
- Security lane complete (46282d0) — S3 supply-chain guard (
checkSupplyChain.mjs: no off-registry/wildcard deps, lockfiles present; clean 26 deps) +npm auditin CI. Joins S1 brain-purity + S2 secret scan →npm run security:all(3 green)- blocking CI
securityjob. (Semgrep SAST omitted — needs an external binary.)
- blocking CI
- Persistence models (8d79818) — the six additive tables (BrainConversation/
Message, GeneratedRecipe, GeneratedPlan/Item, BrainSolveRun, UserLibraryEntry;
migration = 7 pure CREATE TABLEs) +
store.js(injectable accessor, Law-2 guard rejects any exclusion-like key). Dormant until a route wires it. - Full taste-tier system (4085f01) — 4 additive Recipe columns +
taste.js(clampProposedTier / Bayesian-shrinkage effectiveTasteScore) + aw_tastescorer term (0 when no signal → byte-identical) +tasteSeed.json/seeder (24 curated recipes tagged) + the ratings route refreshing the aggregate live.
393 tests green. Only spec items still NOT built: the §0b governance/RESUME/ anti-slop scaffolding (judged ceremony — PROGRESS.md + memory + CI cover the substance) and Stage L fitness (spec defers it). The v2 program is otherwise complete.
- Pushed: all 12 commits are on origin/master (public repo now has the full v2).
- Installer rebuilt:
release/Cut Protocol Setup 1.0.0.exe(200 MB) has current code — the desktop app now matches the dev build. (Personal build: bundles keys + DB — do NOT share it;npm run dist:checkis the guard if you ever do.) - Security lane (Stage S) started:
scripts/checkBrainPurity.mjs(S1) — asserts the brain carries NO web/shell/file-write/eval capability (Laws 5/6); CLEAN over 33 files. Wirednpm run security:all(secret scan + purity) + a blocking CIsecurityjob. Live app confirmed on localhost:5174 (Engine 10-formula verified in browser).
Honest v2-completeness (Shad asked): DONE = the user-facing core (coach planner, E1/E2/T/K + protein fix) + partial Stage S. NOT done (deferred to a fresh session, migration-heavy — cramming them into an exhausted context is the slop the anti-slop stage exists to prevent): the full taste-tier system (tasteTier enum/shrinkage/ curated seed/scorer term), the 6 persistence models (BrainConversation/Message, GeneratedRecipe/Plan, BrainSolveRun, UserLibraryEntry + migrations + store), the rest of the security lane (S3 supply-chain, semgrep, security.yml), the §0b governance/ RESUME/anti-slop scaffolding (judged ceremony), and Stage L fitness (spec defers it).
Next session: "build the remaining v2 parts" → taste → persistence → security lane, each committed + verified like today.
Simulation-driven. A coverage sim (1,200 sampled users, real engine targets, actual week solver) showed the library met only 61% of users on the strict bar (kcal AND protein within 15%, 6/7 days), and vegetarian/vegan = 0% — not a count problem (vegetarian had 320 recipes) but protein DENSITY: plant recipes can't hit a cutting protein target, and you can't scale a low-protein dish up without blowing past calories.
Fix: added 6 dense foods (seedHighProteinFoods.mjs: seitan, TVP, edamame,
pea protein, lentil/chickpea pasta) + a genProteinForward.mjs generator (big
protein portions, protein-rich carbs, minimal fat → high g-protein/kcal). +~160
verified protein-forward recipes.
Result (pool 633 → 889):
| Diet | before | after (adequate / usable) |
|---|---|---|
| Overall | 61% | 83.8% / 89% |
| Omnivore | 75% | 91.8% / 95.4% |
| Vegetarian | 0% | 55.7% / 66% |
| Vegan | 0% | 52.5% / 61% |
Omnivore essentially hits the 95% bar (usable). Plant diets went 0 → 52-56%
adequate — hugely improved, still the laggards (diminishing returns per batch;
the strict daily-protein bar is inherently hard for plant diets). Reproducible:
run seedHighProteinFoods.mjs then node genProteinForward.mjs | genLibrary.mjs.
Honest finding first: the pool was already 633 recipes + the solver is already $0 + Stage 5 likes = favorites, so K's premise was largely met. You chose the full library anyway — so I built it the smart way (no ~$20-50 API spend).
What I added: +98 VERIFIED recipes (633 → 731), $0. Every one gated by the same verifier the app uses — real foods only (no invented ingredients), sane macros (Atwater), deduped. The one real gap closed: vegan 72 → 107 (+49%), vegetarian 275 → 320. Solver still lands 98% on the enlarged pool.
Reusable tooling (committed, so you can expand anytime — no session needed):
backend/scripts/genLibrary.mjs— the harness: reads a drafts JSON, matches each ingredient to a REAL food (token-subset, reject-on-miss — no USDA, no placeholder), validates macros, dedups, persists as source "ai-generated".--dry-runto preview.backend/scripts/genComboDrafts.mjs— combinatorial draft generator (cuisine- flavoured protein×carb×veg×fat) → pipe into the harness. Produced 80 of the 98.backend/scripts/library-seeds/batch01.json— the 18 hand-written recipes (reproducible).
Where the recipes live: your dev.db (gitignored, like all runtime data) — your running app has them now. The tooling above regenerates them on any fresh DB.
Status: 383/383 tests green, golden byte-identical (DB recipes don't touch fixtures), scripts secret-scanned clean. Library is easily expandable (breakfast/ snacks/more cuisines) by running the scripts again.
v2: all 6 stages delivered. Remaining polish: a live UI walkthrough (servers were stopped), and pushing (held per your call).
What you get: thumbs 👍/👎 on each recipe (Recipes tab). Liking a recipe makes the solver prefer it in future plans; disliking pushes it down — a SOFT re-rank only. It never overrides your diet/allergy rules and never changes a macro.
How (all additive, golden byte-identical):
- Migration
add_recipe_rating: a single CREATE TABLE RecipeRating (plain columns, no FK — orphan ratings for a deleted recipe are harmless). Applied + verified. buildBiasgained a taste term: liked ×1.6, disliked ×0.35 (soft, never excluded). No ratings → null bias → byte-identical (proven by the golden + a unit test).- planContext loads the user's ratings as a Map; threaded into /generate, /day-options, AND the chat planner (taste-aware chat plans too).
- New
routes/ratings.js(GET/PUT/DELETE, validates rating ∈ {1,-1}) + registered. - Frontend: thumbs on the recipe detail (optimistic, click-again to clear; selection = lightness, NO red on dislike — constitution-compliant).
Verified: 383/383 tests green (+3 taste bias), golden BRAIN=off byte-identical, oxlint + build clean. Real-data smoke: liked a recipe → planContext picked it up → taste-aware chat plan solved (97%) → cleaned up (0 rows left).
Next (last one): Stage 6 — K (pre-solved library, ~$0 common case). Its generation step is the API-key-vs-subscription question: I can generate the library myself in-session for $0 (verifier-gated), or you pay ~$20-50 for a fast API batch.
What you get: on the Profile tab, a "Estimate visually" button opens a picker — 6 abstract silhouettes (10–35%) you tap to set your body fat, plus an "I had it measured" numeric entry and a "Not sure — skip". Setting it unlocks the Katch–McArdle/Cunningham formulas and refines your estimate. The raw % input stays for power users.
How (add-column, per your call — safest):
- Migration
20260721071636_add_bodyfat_source: a singleALTER TABLE ADD COLUMN bodyFatSource TEXT— NO table rebuild. Applied to dev.db (backed up first); verified: all 4 profiles intact, every target unchanged, new column = null. bodyFatPct stays0 = unknown, so no=== 0touchpoint changed. - Backend: bodyFatSource added to PROFILE_FIELDS + defaultProfile + a validator
(enum
visual-estimate|measured|null). Writes flow through the existing field loop. - Frontend:
BodyFatPicker.jsx— parametric abstract silhouettes (monochrome currentColor, never a real person), constitution-compliant (selection = lightness not green, NO red/green judgment, % labels only). ProfileTab opens it as a modal; saves route through putProfile → target re-materializes server-side.
Verified: 380/380 tests green (+E2 validation), golden BRAIN=off byte-identical, oxlint + build clean, migration verified against real data. (Picker not browser-tested — dev servers stopped; logic tested + save path is the standard field write.)
Next: Stage 5 — T (taste tier: soft palatability re-rank + recipe ratings).
What you get: the Engine tab's BMR panel now offers 10 published formulas instead of 6 — FAO/WHO/UNU, Owen, Livingston, Nelson added — each with a citation. Crucially your target does not move: the 4 new ones are default-off, so the average still runs on today's 6. Tick any new one on (same toggle) to include it.
How (Option A = default-preserving):
- A0 first (8230772): added a BMR golden capturing today's 6-formula mean, so the change is provably byte-identical. null and 0 body-fat confirmed identical.
- 4 formulas appended +
leanBodyMassextracted (single-sources the 3 LBM formulas).DEFAULT_ENABLED+isFormulaOnflip:excludedFormulasmembership FLIPS a formula from its default — for the legacy 6 this is byte-identical to the old opt-out; the 4 new are default-off (opt-in via the same toggle). - Added
sd+spreadPct(+ an honest "dispersion, not a CI" caveat on the tab) andprov {formulaId, inputs, value, citation}on every row (Law 3). Engine now dual-accepts body-fatnullOR0as unknown (readies E2). - Frontend: EngineTab toggle made flip-aware (reads server
defaultOn); "6 of 10" shows automatically; spread caveat added.
Verified: 379/379 tests green (+5 E1 regressions incl. published values for all 4 new formulas + flip semantics). Golden BRAIN=off byte-identical PASSES — proof no target moved. oxlint + vite build clean. (Not browser-verified — dev servers were stopped; logic is tested + data-driven.)
Next: Stage 4 — E2 body-fat visual picker (nullable migration — a real DB change; data-preserving table rebuild, I'll flag it as a rebuild, not destructive).
What you get: it's now hard to leak secrets by accident.
npm run scan:secrets— scans every tracked file for real secrets (Anthropic/ JWT/USDA/AWS/PEM keys, seed passwords). Also a CI job — a committed secret now fails the build. Repo scans CLEAN today (279 files).npm run dist:check— before sharing an installer, scans a builtrelease/for secrets AND personal data (emails in the shipped DB/env). PROVEN: it FAILS the current-style build (catches all 4 real .env secrets + your email + DB personal data, redacted) and PASSES a secretless build.- Placeholder-aware (skips
change-me/ci-only/example…) so docs/CI dummies don't false-positive, without weakening the catch on a real key.
Brain-purity guard: already covered — brainMock.test.js asserts BRAIN=off →
zero LLM calls, and the golden test asserts byte-identical output. No new test needed.
Deliberately deferred (needs your call): the fully-automatic safe dist:share
(secretless env + depersonalized seed DB) needs a decision on which DB tables are
LIBRARY (ship: Food/Recipe) vs PERSONAL (strip: User/Profile/WeighIn/Plan/Diary/
Training/Brain*). I won't guess that with your personal data at stake — it's the
one Stage 2 item flagged for you. The scan+gate above already PREVENT an accidental
leak in the meantime. Dropped the wip-branch/save-resume ceremony (low value).
Verified: 374/374 tests green (+4 scanner self-tests), scanner proven live (clean repo / catches real .env), gate proven both ways. CLAUDE.md caveat updated.
Next: Stage 3 — E1 10-formula BMR (Option A, byte-identical).
What you get: ask the coach "plan me a high-protein day" (or build/generate/ make … a day/meal plan) and it now returns a real, engine-computed day as a card in the chat bar — each meal with its recipe name + P/C/F, a day total, and your target. Every number is the deterministic solver's (LAW 1); the coach's text states no number. Ideas/swaps/follow-ups ("vegan dinner ideas", "why not fish?") still get the normal conversational reply — the plan-route is narrow.
How it's built (all additive, byte-identical-off):
- Extracted
planContext/filterRecipePool/parseFiltersout ofroutes/plans.jsintolib/planContext.jsso the chat planner and every /plans route build the SAME exclusion-filtered pool (M8 single-source). Route re-exports filterRecipePool soplanLogic.test.jsis untouched. Verbatim move — zero behavior change. - New
lib/brain/chatPlan.js:looksLikePlanRequest(narrow intent regex) +generateDayForChat(calls the deterministicgenerateDayCandidateswith NO profile → no LLM, no spend; pool already compliant) +planIntro(number-free). chat.js: plan-route fires AFTER the domain gate (injection still refused first), BEFORE any model call; failure falls through to the coach (LAW 7).- Frontend
BrainChat.jsx: constitution-compliantPlanCard(macro triad only, no green/no red, lightness elevation, "computed by the engine" microcopy).
Verified: 370/370 backend tests green (was 359) — incl. golden BRAIN=off byte-identical + planLogic (extraction held) + 11 new plan tests. oxlint + vite build clean. Not yet browser-verified live (next: a quick real-key smoke).
Next: Stage 2 — governance/security Tier-1.
4 parallel design agents delivered implementation-ready plans (K library, T taste, E1/E2 BMR+body-fat, S+governance). Build order (each additive, byte-identical-off, committed, pause-able):
- Coach planner-wiring — deterministic day-solver → engine numbers → plan card in the bar
- Governance/security Tier-1 — gitleaks secrets + brain-purity regression guard + save/resume
- E1 — 10-formula BMR (Option A default-preserving → targets unchanged)
- E2 — body-fat picker (nullable migration; shares E1 engine)
- T — taste tier (dependency-free types.js; scorer/pool/constraints; opt-in)
- K — pre-solved library (~$0 common case; ends with a one-time ~$20-50 generation on Shad's go)
Decisions: E1 Option A (recommended) vs B (shifts every target); K generation spend (Shad's go, LAST step of K); rest take agent-recommended defaults — dependency-free enums (no zod dep), nullable body-fat, drop wip-branch ceremony, S3 advisory-first.
.template (extraResources) — fine for the personal build, MUST be stripped before
sharing. Split dist:local (keeps secrets) vs dist:share (placeholders + empty DB) +
S4 installer gate scans extracted CONTENTS (filename globs miss the renamed files).
Other reconciliations found: bodyFatPct is currently Float NOT NULL (0=unknown), not
null — engine must dual-accept 0 OR null; A0 null-BF BMR golden doesn't exist yet
(add before touching FORMULAS); UserLibraryEntry lands in K (not I).
Next: start #1 (coach planner-wiring) on Shad's go.
Finished (live-verified on the real key):
- Coach #1 — genuinely useful replies: conversational classifier (greets, follows up), search-only toolset (was flailing on the plan-building tools), no-numbers prompt. Greets, gives real meal ideas from the pool, refuses off-topic. (cc4c1e5, fee0555)
- Coach #2 — conversation memory: client sends recent turns; brainChat caps + validates + prepends. "why not fish?" now stays in context. (d54b584)
- Empty tool-loop degrades honestly instead of a false off-topic refusal.
In flight: 4 parallel DESIGN agents scoping the independent v2 stages (K library, E1/E2 BMR+body-fat, T taste, S+governance). S+governance landed — drop the wip-branch ceremony (keep crash-safe state); installer ships real secrets (S4 scans extracted contents); 2 decisions for Shad (S3 dep-pinning enforce-vs-advisory; distribution extraResources split). Tier-1 security to build first: gitleaks secret scan + brain-purity regression guard + .agent/save-resume.
Next: coach #3 — wire the deterministic day-solver into chat so "plan me a day" returns a real math-checked numbered plan (engine numbers = LAW-1-safe).
Needed from Shad: nothing blocking; the 2 security decisions can wait.
Where we are: the original A–J brain is built, verified (12-agent fleet), and LIVE on a real key — every safety guard proven (no invented numbers, off-topic refused, injection-safe). Live testing showed the v1 Beta Coach is thin: it redirects to the Plan tab on any number, can't follow up ("Why not?"), and can't generate a plan in chat.
v2 plan (coach-first ordering):
- Make the coach's replies useful — prompt tuning so it gives real food guidance instead of a bare redirect. (this step)
- Conversation memory (v2's fuller Stage I:
BrainConversation/BrainMessage) → follow-ups like "Why not?" work. - Wire the planner into chat → the coach produces real, verifier-checked plans in the bar (not a bounce to the Plan tab).
- Then the rest of v2 — E1 (10-formula BMR), E2 (body-fat picker), T (taste), K (pre-solved library → ~$0 common case), L (fitness, deferred) — with the governance/RESUME infra + anti-slop + security lane layered in as we go.
Finished this step: (see next entry once committed) Next: conversation memory (Stage I). Needed from Shad: nothing right now — re-test the coach after the prompt fix.
Standing invariants (unchanged from the original build): every stage leaves
main green and, with BRAIN=off, byte-identical to today; the 7 LAWS win over
everything; no push without Shad's say-so; keys are Shad's to place (never handled
in chat).