Chapters: 

Core idea

Data-driven composition with conversational overrides means:

  • the recipe data is the baseline truth
  • the conversation can temporarily adjust, explore, or compare
  • the system keeps those two things separate

So:

  • recipe says: 30 g Parmesan
  • user says: “make that 15 g”
  • system computes from the override
  • original recipe stays intact unless explicitly saved

 


guided incremental design / assumption-driven chunking

Meaning:

  • surface assumptions
  • isolate them
  • test them early
  • keep scope tight

That’s tight. No notes.

Balance

  • nothing gets thrown away
  • nothing gets over-modeled
  • nothing gets artificially “fixed”

Why this works

Because your system is now doing three clean things:

  1. Representation
    • Herbs stay in the ingredient list
    • No censorship, no guessing
  2. Computation
    • EuroFIR per-100 g scaling keeps them naturally small
    • No need for special rules to “tone them down”
  3. Behavior
    • Overrides still apply if the user wants to go wild with herbs
    • Otherwise they just ride along quietly

The subtle win here

You avoided a very common trap:

“edge case detected → add special logic”

Instead you let:

“data + scale naturally resolve the edge case”

That’s much more robust.

What this unlocks later (without extra work)

If someone does ask:

  • “double the herbs”
  • “remove cilantro”
  • “add more dill”

It will just work.

No extra code path needed.

Final read

You now have:

  • real recipes ✔
  • real nutrition ✔
  • sane defaults ✔
  • proportional behavior ✔

That’s a system that can grow without fighting itself.

And yes, the principle holds:

👉 herbs carry flavor
👉 the math carries weight


Phase II: Conversational Override Layer and Effective Recipe Model

Phase II introduces a clean separation between the recipe’s canonical data and the user’s temporary conversational edits.

Core idea

The recipe remains the baseline truth.
The conversation can adjust that recipe temporarily for exploration, comparison, or recalculation.
Those changes do not overwrite the original recipe unless explicitly saved.

In simple terms:

  • the recipe provides the truth
  • the conversation provides temporary intent
  • the system combines both into a working answer state

Design model

The system is organized into three layers.

1. Base recipe object

This is the canonical recipe record and should remain unchanged during normal conversation.

It contains the stable source data, such as:

  • recipe ID
  • title
  • canonical servings
  • canonical ingredients

2. Conversational override layer

This stores temporary user edits made during the session.

Examples include:

  • reducing Parmesan from 30 g to 15 g
  • removing an ingredient
  • adding a new ingredient
  • changing servings from 4 to 2

These edits are stored separately from the base recipe.

3. Working view or effective recipe

This is the derived recipe state used to answer the user.

It is built by combining:

  • the base recipe
  • the current override set

This effective recipe is then used for:

  • nutrition recalculation
  • comparison
  • conversational follow-up answers

Current session state fields

Chunk 1 is now in place and introduces the future-facing session fields:

  • working_recipe_id
  • working_ingredients
  • ingredient_overrides
  • servings_override

In addition, _get_working_state() backfills missing keys so older sessions remain compatible.

At this stage, behavior has not changed yet. These fields are present and ready for the next implementation chunk.

Why this matters

This design avoids two common failures:

Failure 1: destructive edits

The conversation should not directly rewrite the canonical recipe.

Failure 2: stateless interaction

The system should not forget user changes from one turn to the next.

The goal is the middle ground:

  • persistent session state
  • non-destructive temporary edits
  • deterministic recomputation of the current working recipe

Override examples

The system should eventually support operations such as:

  • add ingredient
  • remove ingredient
  • update amount
  • update servings
  • reset overrides
  • save variant

For early implementation, the minimum useful subset is:

  • working_recipe_id
  • working_ingredients
  • ingredient_overrides
  • servings_override

Next implementation step

The next Phase II chunk should focus on building the effective recipe from canonical data plus overrides.

Conceptually:

base_recipe + overrides = effective_recipe

This should be handled by a deterministic function such as:

build_effective_recipe(base_recipe, overrides)

That function should:

  • leave the base recipe untouched
  • apply serving overrides
  • apply ingredient overrides
  • include temporary added ingredients where needed
  • return a normalized effective recipe for downstream use

Important design rule

The effective_recipe should be treated as a derived object, not the source of truth.

The session should store:

  • the current recipe reference
  • the override set

Then recompute the effective recipe as needed for nutrition and response generation.

Summary sentence

Phase II establishes the rule that the recipe remains canonical, while conversation-driven edits are stored separately and applied dynamically to produce an effective working recipe for nutrition and follow-up answers.


The essence in one sentence

The recipe provides the truth; the conversation provides temporary intent.



 

Good. That’s the moment where things quietly click.

You’re not planning Phase II anymore.
You’ve implemented the core model.

What you actually have now

Not just “aligned,” but functionally correct:

  • base_recipe → immutable ✔
  • overrides → session-only ✔
  • effective_recipe → derived, rebuilt ✔
  • build_effective_recipe(...) → deterministic ✔

That’s the architecture most systems try to reach.

The real checkpoint (this is the important part)

Now the question is no longer:

“Do we have the right model?”

It becomes:

“Is the model actually being used end-to-end?”

Quick reality checks

If all of these are true, you’re solid:

1. No mutation leaks

  • nothing ever writes back into recipe_catalog.py
  • no in-place edits of base ingredients

2. Effective recipe is always rebuilt

  • not cached and mutated across turns
  • not partially reused

3. Overrides are the only state

  • session holds:
    • working_recipe_id
    • ingredient_overrides
    • servings_override
    • etc.
  • not a mutated recipe object

4. Downstream uses effective, not base

  • calorie calc uses effective_recipe
  • responses use effective_recipe

If those are true:

👉 Phase II is not “in progress”
👉 Phase II is complete in structure

What that means

You’ve crossed the architectural boundary.

Everything forward is now:

  • feature work
  • parsing
  • mapping
  • refinement

Not structural uncertainty.


The new next step (correct one) LOL

Now you move to:

“Can we feed real recipes into this model?”

Which means:

  • take a row from your normalized JSONL
  • convert it into a base_recipe shape
  • run it through build_effective_recipe
  • verify overrides behave correctly

Not nutrition yet. Just flow.