Recipes & Production — how a made item becomes the ingredients it consumed¶
What this covers. A restaurant doesn't sell flour and eggs; it sells a carbonara. But the stock behind that carbonara is flour and eggs, and they have to leave inventory at a real cost. This chapter is about the food layer that sits on top of the stock books: the recipe that says what a producible item is made of, why recipes are versioned so the cost of a sale made in March is still computable in June, how a sold made-to-order item is unpacked down to the raw materials it actually used (using the recipe version that was in force on the day it sold), what a prep item is — formally, a semi-finished good: a thing you make in advance and keep in stock, like peeled carrots or a base sauce — and why its yield emerges from its own recipe instead of being typed in. It ends with production (making a prep item is just two ordinary stock movements, posted at the quantities the session recorded) and theoretical-vs-actual variance (what the recipes say you should have used versus what the count says you actually did), and what happens when a recipe turns out to have been wrong — a schedule repair settled at the close, never a rewrite of history. Throughout, keep one thing in mind: a recipe is far more than the parts list this chapter leans on — it is the company's recipe knowledge base (§1).
1. A recipe is the company's recipe knowledge base¶
A recipe is the company's recipe knowledge base — far more than a parts list. It is the durable, versioned record of how a thing is made, and it does several jobs at once:
- The parts and quantities — the structured ingredients: per portion, 110 g spaghetti, 45 g guanciale, 1 egg, 18 g pecorino — plus the packaging it ships in.
- How to actually make it — free-form preparation steps, plating and packaging instructions, photos, and notes: the craft a bare parts list can't hold.
- The evidence every food calculation reads — the very same recipe is what the nutrition, shelf-life, and allergen logic reads to reach its answers (see Food attributes); the richer the recipe, the better those answers.
- How cooks learn and are checked — a new cook learns a product from its recipe and is attested on it (answering questions about its details), and a cook preparing a batch opens the recipe on a tablet to remind themselves of the method.
A recipe may describe how the same cooked output is packed for each fulfillment. A packaging variant carries a localized description, packaging materials, steps and media, and belongs to one fulfillment — dine-in or delivery — or to none, which makes it the recipe's general variant. A recipe keeps at most one of each. A sale is packed by the variant for its channel's fulfillment, otherwise by the general variant, otherwise not at all; a sale that names no channel, the recipe's plate cost and its shelf-life evidence read the general variant alone. Variants are optional and need no authored name: the box items, instructions and finished view are what tell cooks how one packing differs from another. A genuine fork in the cooking method is a separate item and recipe, not a packaging variant.
This chapter is about the one facet the stock books depend on: the structured ingredients, which form a bill of materials (BOM) — the manufacturing term for a list naming the parts of a product and how much of each, the same idea a car factory uses to say "one car = four wheels, one engine, one chassis." The recipe's other roles — the how-to-make-it craft, the training, the food-calculation evidence — are the same artifact serving the wider operation; they live in Catalog and Food attributes.
Why does the stock side care about recipes at all? Because of the one-way boundary explained in Sales & consumption: the selling side reports "12 carbonaras sold," but it has no idea what a carbonara is made of. A made-to-order item, by itself, depletes nothing. Its recipe is the only thing that knows those carbonaras became 1.32 kg of spaghetti and 12 eggs leaving stock. So the recipe is the bridge between "this item was sold in portions" and "these ingredients left, at this cost." Get the recipe wrong and the food-cost number is wrong.
2. Why recipes are versioned — the problem they create for the books¶
Here is the trap, and it's the reason almost everything in this chapter is shaped the way it is.
A recipe is not a fixed fact — it changes over time. The cheeseburger sold on 1 March used a different patty than the one sold on 1 June; somebody changed the dough hydration in April; a supplier swap nudged the cheese in May. That's normal. But now think about re-costing a past sale. A delivery platform back-reports a March order in July. An auditor restates last quarter. A variance review asks "what did that 1 March carbonara actually cost us?" If the books only ever stored the current recipe, every one of those questions would be answered with the June recipe — and produce a number that is wrong, and worse, unreproducible: ask again next month and you'd get yet another answer.
So the rule is:
The cost of a past sale must be computable forever, from the recipe that was actually in force on the day of that sale.
The way the domain guarantees this is a principle worth naming: immutable by reference. Once the books have relied on a recipe version, it is never edited again. Changing a recipe doesn't overwrite the version the past leans on — it creates a new version, and the old version stays exactly as it was, quantities and costs and all. Re-costing a March sale looks up the version that was in force in March and walks a recipe that can never change underneath it. The past is frozen because nothing ever writes over it; it only gets superseded by something newer.
This is the same instinct as the close in the stock ledger (see Stock ledger): what a sealed period leaned on is never rewritten underneath it — it is superseded by something newer. Recipes obey the same discipline.
3. How versioning works: write it, then schedule it¶
Each recipe version is its own record. There is no separate "history" file — the history simply is the set of versions that belong to the same owner item. A version carries exactly one scheduling fact: an effective date, or none.
- Off the schedule (no effective date). Freely editable while nothing has relied on it — you can rewrite the ingredients, the portion sizes, anything. A version off the schedule has no effect on the books: nothing is ever unpacked through it. A fresh version starts here, and a version taken off the schedule returns here.
- On the schedule (an effective date). When you schedule a version you give it the business date from which it becomes the truth, and from that moment it is the recipe in force for every date in its window. Ordinarily a version leaves service purely by a later version taking effect after it; unscheduling takes it off by hand instead — for the version that should never have governed at all, not merely been superseded. Its date clears and frees up for another version, and the record itself stays: everything already posted through it remains readable forever. Scheduling it again, on any open date, puts it back.
There is no third state. "Draft", "active", "archived" are not things a version is; they are things a reader says about where it stands, and the schedule says it more precisely. Against any business date every version has a position: unscheduled, upcoming (dated ahead), current (the latest date at or before today — exactly one per owner), or superseded (its date has arrived, but a later version's has too). Those are readings of the date, not extra lifecycle states: the same scheduled version moves through upcoming, current and superseded as the business date advances and later versions take effect. This is why "active" was the wrong word: several versions of one owner are scheduled at once — past, present and future — and only one of them is current.
A version may be ownerless while its composition is being developed. Scheduling joins exactly one item's timeline, because a recipe describes the output of one producible item. That identity becomes fixed when another recipe, a saved list, a production session or recorded consumption uses the version. A recipe for tuna paste cannot become a recipe for egg paste underneath a batch that followed it, even when both recipes happen to use the same quantities. Before that first use, an incorrectly assigned owner can be corrected while its accounting window is open.
The first version may simply establish the recipe. Every later version must carry a short change note: what materially changed since the previous version, such as "supplier pasta changed," "portion resized," or "packaging added." The note is not part of the cooking method; it is the version timeline's audit trail, so an operator can understand why the recipe changed without diffing the whole version. Version numbers follow the order of scheduling — a version that was taken off the schedule and put back takes its place in that order afresh, unless postings already quote it by its old number, in which case the number is part of the history and stays.
The parts that drive the numbers — the ingredient list, the packaging, and the portion count / portion size — stay editable as long as the books are open, and an edit never leaves the books behind: correcting a scheduled version re-explodes, in the same stroke, every open-period sale and consumption that posted through it (directly, or through a recipe that contains it), so the standard and the books tell one story at every moment. Nothing changes silently: a past unpacking is re-costed visibly, as part of the correction itself, and a correction on a scheduled version must leave it in a shape scheduling would accept, with a composition the explosion can walk. The freeze is the close: while a close in force has priced consumption through a version, that composition stays fixed, and the correction is a new version — duplicate the current one, fix it, schedule it on an open date. The same sealed reliance is what keeps a version taken off the schedule from being deleted or given a new owner: it is history, not a sketch. Production has a different source of truth: what the shift took and made, together with the component amounts it either measured or borrowed from a recipe. Correcting those borrowed amounts requires a decision about the affected sessions, as explained in §8. Deleting a draft version disturbs nothing recorded: a computed food profile or a batch still being planned keeps its own facts and forgets the version; a sale already recorded against the version's packaging refuses the delete. What doesn't move the numbers never locks at all: the description, the prep steps, photos, cooking time, and the version's change note stay editable on any version — you can fix a typo in step three of the method under a recipe that sells every day.
One version per owner per date — the timeline rule¶
There can be at most one recipe in force for a given owner on a given date. This sounds obvious but it's load-bearing: it's what makes "the recipe on date D" a question with exactly one answer rather than an ambiguous set. If two versions could claim the same effective date, "re-cost the March sale" would be undefined. So a version's effective date is unique per owner, and if you try to schedule a second version on a date that's already taken, the system refuses. Each scheduled version owns the stretch of dates from its effective date up to (but not including) the next version's effective date.
Scheduling is not ordered beyond that. A new version usually lands past the end of the timeline, but nothing forces it to: the timeline over open dates is the operator's to shape, and placing a version ahead of one scheduled earlier is as legitimate as moving one (below). The only edges are the ones every schedule change has — a date a sibling holds, and sealed territory.
The effective date may lie in the past — and why¶
Nothing says the effective date must be in the future. If the current version took effect 15 May and today is 20 June, you may schedule the next version effective 1 June — in the past, and in force from that day on for every date up to the next version's.
Why allow back-dating at all? Because the most common real failure runs backwards: a made-to-order item starts selling before its recipe is recorded. A new item is rushed onto the menu on Friday; the recipe gets written up the following Wednesday. Every Friday-through-Tuesday sale of it is now a sold item with no recipe in force on its sale date — a hard close-blocker (§9): those sales are held, uncosted, because a made-to-order sale must never cost nothing. The resolution is exactly a back-dated scheduling: write the recipe now and schedule it effective on or before the first sale. The held sales resolve a version, unpack normally, and the close can proceed.
Back-dating is safe because the books follow the schedule wherever they are open: the held sales resolve the newly covering version and post through it, and any sale inside the window that had already posted against another version re-explodes to the schedule's new answer as part of the very same stroke. There is nothing to reconcile afterwards — the move and its consequences land together, or not at all; a window that reaches into a closed period refuses instead, because sealed consumption never changes. Every posted depletion remains pinned to the recipe version that explained it (§5), so at any moment the books can still say exactly which standard each row followed.
The effective date is movable — while the books are open¶
Scheduling is the cook's gesture: the recipe is written, it is in force, done. Where its window starts is bookkeeping, and bookkeeping should never make the cook wait — so the effective date given at scheduling is not a verdict. Whoever keeps the books may move a scheduled version's effective date afterwards, and each role does its work without leaning on the other.
Free movement has exactly two edges. A date another version of the same owner already holds is refused — one version per date is what keeps "the recipe on date D" a question with one answer. And sealed territory is settled: a date at or before any warehouse's latest close can be neither left nor landed on, because every closed period read the schedule as it stood, and the seal is a promise that what it read stays true. Between those edges the timeline over open dates is the operator's to shape — including placing a version ahead of one scheduled earlier.
The everyday use is the back-dating story told in reverse. A made-to-order item's sales were rung up before anyone scheduled its recipe; the recipe was then scheduled from today, so the schedule still has no answer for the sale dates and the sales stay held. The fix is one move: pull the version's effective date back to the first sale. The move recomputes nothing — it changes what the schedule answers, and the held sales, now covered, record normally.
Moving and unscheduling compose into the repair for a version that was simply wrong: sales posted through a badly written version, a corrected version is authored and scheduled, the bad one is unscheduled — freeing its date — and the corrected one is moved onto it. The postings made through the bad version don't vanish and aren't quietly forgiven; they now disagree with the schedule, and the close holds the period until that disagreement is settled.
Worked example — resolving the recipe on a date¶
The item "Roast Carrot Plate" has three scheduled recipe versions; today is 20 June:
| Version | Effective from | Window it governs | Position today |
|---|---|---|---|
| v1 | 2026-01-10 | 10 Jan – 1 Mar (exclusive) | superseded |
| v2 | 2026-03-01 | 1 Mar – 15 May (exclusive) | superseded |
| v3 | 2026-05-15 | 15 May – onward | current |
The rule for "which version governs date D" is: the scheduled version whose effective date is the greatest value still ≤ D. So:
- A sale on 20 Feb resolves v1 — the most recent version at or before that date.
- A sale on 1 Mar resolves v2 — the boundary day belongs to the newer version (the test is "effective date ≤ D").
- A sale on 1 Jun resolves v3.
The uniqueness and ordering rules above are what guarantee this lookup always returns exactly one version. This is the same "recipe actuality" rule the catalog uses: one recipe in force per item per date (see Catalog).
4. The recipe is a tree — and there are two ways to nest¶
An ingredient line points at one of two things, and never both:
- an item — flour, oil, a bought-in good, or a stocked prep item like dough. If the item is a plain material, the line is a leaf: there's nothing further to break down. If the item has its own recipe (a prep item does — §6), the line is a live link: every explosion resolves that item's recipe by date, with the same greatest-effective-date-≤-D lookup as §3; or
- a pinned version of another recipe — not "the dough recipe" in general but "dough, v7": one specific, frozen version.
Because a line can point into another recipe — which has its own lines, which can point deeper still — a recipe is really a tree that bottoms out in raw items. A made-to-order item references dough; the dough references a starter; the starter references flour and water. Walking that whole tree down to the raw leaves is what manufacturing calls a bill-of-materials explosion — exploding the made item into the full flat list of raw materials behind it.
A tree has to bottom out, so no recipe ever reaches itself — not by pinning its own version, and not through any chain of items and recipes in between. Every version counts, scheduled or not, because any of them may become the one in force. A recipe that reached itself could never be unpacked down to its raw materials — the walk would circle without end — and its cost would be defined in terms of itself.
A recipe may be a matrix¶
A fixed bill of materials says what one item always is. A made-to-order item may instead need to say everything it can be without pretending that a marketer owns its gram weights. Its recipe then becomes a matrix.
An ordinary line marks its presence: fixed lines are always in the item, removable lines are in unless somebody takes them out, and addable lines stay out unless somebody asks for them. A slot is a named choice place — milk, base, protein — whose candidates carry the item or sub-recipe, amount, and technique that can fill it, and whose selection bounds say how many of them one dish can carry at once, in the same from–to words a modifier group speaks. Exactly-one is the classic radio: a latte holds one milk. A minimum of zero makes "none of them" a legal dish — cheese on a sub — rather than an unanswered question. A wider maximum lets candidates combine: a bowl carries up to three proteins because that is what fits the bowl, a physical fact the technologist owns. The menu may offer the customer a narrower choice than the recipe can carry, never a wider one — a wider offer produces picks the dish cannot seat. Slot names are unique within one recipe so an instruction can name one place unambiguously.
One candidate may be marked the slot's canonical pick — what a recipe page or a half-built order form shows before anyone has chosen, the regular milk a cappuccino is pictured with. It is a truth for the eye, not for the books: resolution never seats an unchosen canonical pick, because stock must leave only for what somebody actually chose. Which choice a sale presumes remains a commercial fact owned by product cards and menus.
This division lets one item identity bridge the two worlds. A menu choice says which catalog item was chosen or removed; the recipe finds that item in exactly one place. The same item therefore cannot appear twice in one recipe version, whether as an ordinary line or a candidate in either slot. An ownerless nested recipe remains valid as an ordinary fixed line, where its recipe identity is enough, but it cannot participate in a choice until it has a catalog item of its own.
A matrix belongs only to a made-to-order item. A stocked prep item is produced from one concrete card, with nobody present to resolve a customer choice, and a recipe with slots is never nested inside another recipe for the same reason. Where candidates genuinely differ by method — omelette, fried, or poached eggs — each may be an owned sub-recipe that keeps its technique with its composition.
Resolving a choice produces a build: the final recipe the cook reads, with the chosen candidates seated in each answered slot, requested addable lines included, requested removable lines excluded, and chosen multiples applied. A slot is answered when its picks reach the slot's minimum; picks beyond its maximum are not a bigger order but a contradiction, refused the same way as two milks in one latte. The authored tree remains the author's matrix — slots stay visible as slots — while the build is its derived, order-specific reading. Wherever a preparation step names a slot, a resolved build reads that place as the chosen candidates' names, each followed by its instruction where one exists. An unanswered slot remains visibly unanswered; a slot whose minimum is zero and which nobody filled reads as legally empty, not as a question still open.
The base build is the one deterministic reading when nobody supplied a choice: fixed and removable lines stay, addable lines stay out, and every slot remains empty. It is an honest absence of choice, not a guessed default — the canonical pick does not sneak in here either.
The two modes propagate changes differently¶
The choice between the two reference kinds is not cosmetic — it decides what happens when a child recipe changes:
- An item reference follows the child as it evolves. The line names the item, not any version of its recipe — so when the prep cook publishes a new version of the dough recipe, every parent item whose line says "dough" picks it up automatically at its next explosion, with no edit to the parent at all. One child edit, propagated everywhere, by construction.
- A pinned reference is a frozen snapshot. The parent names "dough v7" and means exactly v7, forever. If dough moves on to v8, the parent keeps reading v7 until somebody re-versions the parent to point at the newer child. The scheduled parent plus the exact child versions it names form a snapshot that, top to bottom, cannot change — which is the whole point of pinning.
Which to use when? The guidance is simple:
- A stocked prep item is referenced as an item. The consumption unpacking stops at it anyway (§7) — it depletes as itself, at its own cost — and the live link keeps the parent item's rolled-up cost (and nutrition, allergens, and shelf life — §11) tracking the prep recipe as it evolves, with no parent edits.
- A pinned nested version is for non-stocked sub-compositions where the snapshot is the intent — a sauce assembled to order, a spice mix that exists only inside this one made-to-order item. There is no stocked item for the walk to stop at, so the sub-recipe is genuinely part of the parent item's recipe — and it should be frozen together with it.
There's one courtesy scheduling handles for pinned references: while you're still authoring, an unscheduled parent is allowed to point at unscheduled children (you write a whole nested recipe family together). Scheduling won't put a parent on the timeline while it still references a child that is off it, so — with your explicit go-ahead — it schedules the whole referenced subtree together, on the same effective date, in one step. If scheduling one recipe would quietly drag others onto the timeline with it, the system stops and shows you exactly what would go on before you commit.
The children scheduled this way take the parent's change note as their own. They changed because it changed, so that is one reason written once rather than the same sentence retyped against every recipe it reached. A child that already carries a note of its own keeps it — somebody wrote that about this recipe, on purpose.
5. Unpacking a sold made-to-order item — date-correct explosion¶
Now put §3 and §4 together. When a made-to-order item is sold through the front door (the sales ticket of Sales & consumption), the stock side must turn "12 carbonaras" into the actual raw quantities that left stock. For a matrix it first reads the sale's concrete build, or the base build when no choice was supplied. It then explodes that build, using the recipe that was in force on the sale's business date, not the one in force today.
The steps:
- Resolve the root recipe for the sold item on the sale's business date — the §3 lookup, the greatest effective date ≤ that day.
- Pin that resolved version onto every stock movement the explosion produces. This is the linchpin of reproducibility: each consumption movement records which exact recipe version explained it, so a later recipe edit — or a back-dated scheduling (§3) — can never re-explain a movement already on the books. Re-open the movement years later and it still points at the version it was costed against.
- Walk the build down to its leaves — only the lines the build contains, pinned branches exactly as published, item references resolved by the same business date (§4). At each level, scale the child quantities by how much of the parent was requested, recurse into any nested recipe lines (the walk stops at a stocked prep item — §7), and collect a flat list of raw-item quantities. Leaves that turn out to be the same material are merged into one line.
- Convert to base units at the leaf. Every quantity that enters the books is in that item's base unit — grams, milliliters, or each — so the explosion is where recipe quantities (which may be written in any sensible unit) get converted down to the base the ledger speaks (see Units of measure).
Because a version the books rely on can never change, the flattened result of walking one build on a given business date can be computed once and reused for every matching line in a run — it changes only when the build changes or a new version (of the root, or of a date-resolved child) takes effect.
Worked example. 12 carbonaras sold. The recipe in force on the sale date is, per portion, 110 g spaghetti, 45 g guanciale, 1 egg, 18 g pecorino. The explosion yields 1.32 kg spaghetti, 540 g guanciale, 12 eggs, 216 g pecorino — and posts each as a consumption movement, removing it from stock at what that ingredient is currently worth, every movement pinned to the recipe version that explained it.
The selling side said only "12 carbonaras." The recipe is what made that twelve eggs.
6. Prep items — things you make and stock in advance¶
So far a recipe explodes all the way down to raw items in one sale. But real restaurant prep doesn't work that way for everything. You don't peel a carrot per plate at service — you peel a tub of carrots in the morning and keep them ready. You don't mix dough per pizza — you make a batch and portion it. That prepped, stocked, made-in-advance thing is a prep item (formally, a semi-finished good).
A prep item is something with three properties at once:
- it is producible — you make it (you make dough; you do not "make" raw flour);
- it is stocked — it's a perpetually tracked item, with an on-hand quantity and a cost, counted at close like any other stock (see Item model & policies for what "stocked" means precisely); and
- it has its own recipe — the item's dated composition that says what goes into making a batch.
That combination — producible AND stocked — is what makes something a prep item. Note what it is not keyed on: it is not decided by a category named "Prep items." A label like that is a name someone typed, and behavior must never hinge on a typed name (you could rename the category, or spell it differently, and silently break the logic). Prep-item-ness is derived from the stable facts — do you make it, do you stock it — not from what bucket it's filed under.
A prep item's output emerges from its recipe header¶
A prep item's recipe says how much one batch makes. Its header carries a portion count (how many portions a batch yields) and a portion size (how big one portion is). What the batch output is depends on how the item itself is measured:
measured by mass or volume: output = portion count × portion sizecounted in pieces: output = portion count pieces
An item measured by mass or volume makes portions of itself, so the portion size must be in the item's own dimension — a prep item measured in mass can't declare a volume portion. (Dimensions — mass vs volume vs count — never auto-convert into one another; see Units of measure.) An item counted in pieces makes one piece per portion, so its batch is the portion count, and the portion size, when stated, is what one piece weighs or holds. A batch of meatballs with portion count 40 and portion size 30 g makes 40 meatballs, 1.2 kg in all; a cappuccino sold by the cup makes one cup per portion, and its 200 ml is the size of that cup.
These header fields are fixed with the rest of the composition while a close still in force has priced consumption through the version, precisely because they are the denominator of the prep item's unit cost, as the next section shows.
7. Yield is emergent, not a typed-in factor¶
This is the most important costing idea in the chapter, and the one most inventory systems get wrong.
When you prep a raw ingredient, it loses mass. You buy 124 g of whole carrots and, after peeling, you have 100 g of edible peeled carrot. This is the difference between as-purchased (AP) — what you bought and paid for — and edible portion (EP) — what's actually usable after prep. The classic costing rule is EP cost = AP cost ÷ yield%: because some of what you paid for is now peel in the bin, the surviving edible part must carry the full purchase cost, so it costs more per gram than the raw ingredient did. Cost at the as-purchased price and you systematically understate food cost — you pretend the peel was free.
The naive fix that many systems reach for is a yield-percentage field on each ingredient: "carrots, 81% yield, type it in." This domain deliberately does not do that. Instead:
Yield emerges from the prep item's own recipe. It isn't stored; it's computed from ingredients and output.
The reasoning: the moment a prep item has its own recipe (§6), the recipe already contains everything a yield factor would have told you. The ingredients are right there; the output is right there; the yield is just one divided by the other. A typed-in yield factor would be a second statement of the same fact — and two sources of truth that can drift apart is strictly worse than one that can't. So:
yield = prep-item output ÷ Σ(its ingredients, in base units)prep-item unit cost = Σ(ingredient costs) ÷ output
The unit cost already embeds the yield — nothing to type, nothing to keep in sync, nothing to get wrong. And when a parent recipe uses a prep item, it consumes it one-for-one: one gram of "peeled carrot" in a dish is one gram of the prep item, at the prep item's cost. No factor at the point of use, because the cost already carries it.
Where a matrix is read without a concrete choice, its input and output relationship uses the base build. That is the only deterministic yield statement the recipe can make on its own; a concrete build may add a separate costing answer, but it does not rewrite the recipe's canonical yield.
The recipe editor can price this before anything is posted. Any recipe version, including one off the schedule, can be previewed at a warehouse and date without recording history: stocked inputs price at that warehouse's pool price as it stands now, non-stocked inputs price through the sub-recipe in force or latest receipt reference price, and pinned sub-recipes price their frozen tree scaled to the stated quantity. For a prep recipe, the editor's cost per output unit is the theoretical full recipe cost divided by declared output — useful for authoring and margin work, but distinct from what a production posting later puts into the pool.
Worked example — Peeled Carrots (124 g → 100 g, 81% yield)¶
Model "Peeled Carrots" as a prep item (producible, stocked, measured in grams) with its own recipe:
- Input: 124 g whole carrots. Say the warehouse's average cost for whole
carrots is €0.0020 / g → ingredient cost =
124 × 0.0020 = €0.2480. - Output: portion count 1, portion size 100 g → output = 100 g of peeled carrot.
- Emergent yield:
100 g ÷ 124 g = 0.806… ≈ 81%. Nobody typed this. It falls straight out of "we put in 124, we got 100." - Prep-item unit cost:
€0.2480 ÷ 100 g = €0.00248 / g. Notice this is higher than the €0.0020/g raw cost — the 24 g of peel-loss has been correctly rolled into the 100 g that survived. That uplift is the yield, now expressed as cost.
Now the dish — "Roast Carrot Plate" — uses 80 g of peeled carrot. Its recipe references the Peeled-Carrots prep item one-for-one:
- 80 g of peeled carrot ×
€0.00248 / g= €0.1984 of carrot cost in the dish.
And here's the key consequence: because the prep item is stocked, the dish explosion (§5) stops at it. It posts an 80 g consumption of peeled carrot at the prep item's cost and does not keep going down into whole carrots. The peeling already happened — and was already costed — back when the prep item was produced. Descending again would count the carrots twice — and would deplete whole carrots the cooks never touched while the batch of peeled carrots they actually drew down sat untouched on the books. (This is the rule Sales & consumption §4 referred to: the unpacking stops at a stocked prep item.)
The operator chooses how deep to model¶
The very same plate could instead list raw carrots directly in the dish recipe. That's simpler to author — but then the dish explodes straight down to whole carrots, and the 19% peel-loss never shows up as recipe cost; it only surfaces later as count-driven variance (§9). Modeling Peeled Carrots as a prep item buys accuracy (yield captured right in the recipe, prep tracked as real stock); putting raw carrots in the dish buys simplicity. Both are legitimate. The depth of decomposition is a deliberate operator decision, not a system rule.
8. Production — making a prep item is two movements¶
How does a batch of peeled carrots actually come into stock? Not through any special "manufacturing" mechanism. Production is just the ordinary stock engine plus a recipe — a pair of stock movements through a virtual staging point called production (one of the non-physical counterparty locations the ledger uses; see Scope & locations).
For one batch of Peeled Carrots:
- Consume the ingredients. A movement carries 124 g of whole carrots out of the warehouse and into production — at the warehouse's average cost, €0.2480.
- Yield the output. A movement carries 100 g of peeled carrots out of production and back into the warehouse — and that 100 g lands carrying the full rolled-up ingredient cost: €0.2480 over 100 g, i.e. €0.00248/g.
The ingredient value flows through into the output value; quantity is neither invented nor destroyed — it's conserved across a pair of balanced movements, exactly the double-sided discipline the stock ledger uses for everything (see Stock ledger).
A production run records a session, output-first. One document captures the whole prep session — "this morning we prepped: peeled carrots 300 g, sauce 5 L" — with one line per item made, and under each line the ingredients that line consumed. Those ingredient amounts say what each batch is made of, and the session also records what the shift used to make it — the input. Stock ingredients leave the warehouse; consumables and counted consumables remain part of the physical input and composition without a stock movement. Each output lands carrying the stock value its own composition absorbed, so the cost is honest by construction: cost = what the batch absorbed ÷ recorded output.
The material plan does not have to be typed from nothing. Picking a recipe fills it in, scaled to the output the shift recorded: if the recipe declares a 100 g batch from 124 g of whole carrots, recording 300 g of peeled fills 372 g of carrots in. The operator then adjusts what needs adjusting — today's carrots are old and peel at 78%, not 81% — and a correction belongs to the ingredient amount it changed: fixing the carrots does not detach the rest of the line from the recipe.
That makes the recipe two things and neither of them a posting instruction. It is the quick-fill source that saves a cook from writing out a dozen ingredients, and it is the standard the batch is measured against afterwards. What it is not is what production consumes: the material plan records the quantities the session asserted. A later recipe correction can explain why those quantities need review, but cannot itself establish what the shift actually took or made. A line may equally carry a material plan and no recipe at all, which is how a restaurant records production from day one, before any recipes are written.
The plan also records something the recipe cannot know: whether the shift took a prep off the shelf or made it inline. A stew recipe that calls for 400 g of sauce normally means 400 g of the sauce standing in stock, consumed at the pool's price. But a shift that had no sauce made it in the same pan, from tomatoes — so those tomatoes are what left stock, and the sauce never existed to be counted. The operator says which happened, and the plan follows: the prep itself, or the raws it would have been made from, at whatever depth the tree goes. And which recipe those raws come from is the operator's to say too. The book proposes one — the recipe the parent's author suggested, the current standard, or simply the newest version written — and says which it is proposing; the shift may answer with any recipe version for that prep it actually followed, a superseded version or one still being written included. A recipe version's status decides what the catalog holds up as the standard, not what a shift may assert it did — a restaurant whose recipes are all half-written still cooks. Two cases decide themselves, because there is nothing to take off a shelf: a non-stocked sub-recipe and an ingredient the business does not keep stock of at all. Both always stand in for their own raws.
The declaration is part of the sheet. The sauce row stays where the recipe put it, marked made inline with the version the shift followed — or with none, when the cook made it by hand — and its raws sit beneath it, each raw free to be opened the same way in turn. The row itself is never consumed and never costed: what the sheet says about it is the quantity it stood at when it was opened, so that a reader sees "400 g of sauce, made from these" rather than a loose list of tomatoes with no explanation. Open the document a week later and it reads exactly as the shift wrote it.
The document is a process, so it starts as a draft. A run is written by a person, and in a real operation the cook who writes the sheet is rarely the person who signs it off at the end of the shift. So a session opens as a draft: freely editable, holding as much or as little as the shift has managed to write down, and touching no stock at all. Posting is the gesture that asserts it, and it asserts the session whole — every line's move-pair or none. The one thing a line cannot do is yield something out of nothing: a line with no input standing behind what its composition names refuses, nothing posts, and the document stays a draft with the reason named against each line, because the output needs physical inputs that account for its composition. A batch made entirely from expensed ingredients has real inputs and a legitimate zero capitalized cost. Book stock is never among the reasons a post is refused: the batch was already made, so the draw posts even when the book cannot cover it — the ingredient pool goes negative at its own price, and the missing receipt or the next count settles the debt (the book never refuses a fact; see Invariants). A posted session is corrected by correcting its sheet — the draws and the yield are recorded again from what it now says — for as long as its period is open, and the loss gate is asked over again with it: a correction that moves what the shift writes off needs the shift's answer for the new figure, not the old one. If the corrected sheet is unfinished, does not balance, or records a loss nobody has accepted, the whole session returns to draft and its earlier movements are withdrawn. The corrected facts remain a working sheet until they are settled and posted again. A correction that still balances with accepted losses keeps its posting; saving alone never accepts a new loss.
One deliberate accounting distinction sits underneath all of this. The editor's recipe cost preview is the theoretical full cost of the recipe, including expensed leaves, because it answers "what does this recipe cost to make?" A production run capitalizes only the stocked ingredients it actually consumes into the output pool. Any expensed leaves have already hit profit-and-loss where their treatment says they belong, so pushing them into the produced item would double-count them.
Trim-loss is implicit. Output (100 g) weighs less than the ingredients (124 g), but the output carries their full cost — so the 24 g of peel needs no separate entry. Its value simply lands in the 100 g that survived, which is exactly where the EP/AP rule (§7) says it belongs. (Logging the trim as an explicit waste movement to the scrap location is a possible later refinement; the cost result is the same either way.) This is a different thing from production loss: trim is the gap between what went in and what came out, and it belongs in the output's cost; a production loss is the gap between what the batch planned to use and what the shift says it used, and it belongs nowhere near the output.
The payoff of treating production this way: stockable prep items, commissary prep (a central warehouse that makes batches for several restaurants — its batches reach each restaurant's own stores by explicit transfer; see Scope & locations), and a forward production plan all fall out of one primitive — a consume-then-yield pair — instead of each needing its own bespoke machinery.
What the shift took — the input¶
A prep sheet has two halves and they are not the same number. Under each output line sits the composition: what that batch is made of, and in what quantities — the recipe's numbers, or the cook's own. Alongside them, at the level a shift can physically measure it, sits what the shift took off the floor: "flour, 12 kg total." That second figure is the input, and it is the consumption fact. It is what left the store, so it is what the books read.
This is why a session must say it out loud. Composition alone is a plan — a statement about how a batch is built, not a statement that anything happened. A session that records no input at all has nothing that left the floor, so its outputs would be minted from nothing, and it will not post until somebody says what was taken. A shift that worked exactly to its composition simply says so.
Per item, across the whole session, the sheet has three figures and they have to balance:
input 400 g what the shift took off the floor
composition 372 g what the batches account for
loss 28 g what left the floor and no output absorbed
372 g → the batches at pool cost, as always
28 g → production loss at the same cost, to stock loss
What was taken is what the batches absorb, plus what was lost. Nothing else closes, and a sheet that does not close does not post. The two ways it fails to are worth naming:
- More than the composition accounts for. The excess posts on its own as a production loss — it left the floor and no output absorbed it, which is what loss means. Crucially it never touches a batch: waste does not raise the peeled carrots' unit cost, and so never leaks into the cost of every product built on them. A recipe that is chronically wrong shows up as a steady loss stream pointing straight at itself. And because the shift recorded it, the close reads it like documented waste — explained, never unexplained shrinkage.
- Less than the composition accounts for. The sheet contradicts itself: the batches claim more of the item than anyone says left the floor, and no loss can absorb the difference, because a loss cannot run backwards. So the session is handed back to the shift. Somebody weighed something wrong or forgot a sack, and only the people who were there know which — a guess made on their behalf would cost every batch on the sheet a little less than it really cost.
- An item nobody said they took. Nothing left the floor, so the composition naming it stands behind no fact at all — the same contradiction, and the same answer. A stated zero says it out loud rather than by omission, and reads the same way.
- An item taken that no composition names. The whole quantity is production loss. It left the store and no output absorbed it — which is exactly how the fish taken on a meat-burger shift books, with no machinery of its own.
When several lines share an item, each line's composition draws exactly what it says: the input covers all of them or the session does not post, so no batch is ever handed a share of somebody else's weighing. The loss, being a fact about the session rather than about one batch, is recorded once per item.
Nobody loses stock by accident¶
A loss is value leaving the books, and the session will not book one until somebody has looked at the figure and accepted it. The shift is shown what would be written off, item by item, and answers for it before the session posts — a shift that lost nothing has nothing to answer and is never asked.
What is accepted is a number, not a promise. Re-weigh afterwards so that a different amount is written off, or so that a second item joins it, and the acceptance no longer covers what the session would book: the shift is asked again, against the new figure. Re-weigh so the loss disappears and there is nothing left to answer, so the session posts. This is what stops a mistyped input from quietly writing off a sack of flour — the value that leaves the books is always a number somebody read.
Recipe-authored amounts follow the recipe until the cook changes them¶
Filling a line from a recipe leaves its component amounts under recipe authorship: reweigh the output on the working sheet and every still-authored amount scales with it. The moment a cook writes or corrects an amount, that amount is theirs — it holds its number however the batch is resized afterwards, and it is what the books will take. The output itself is always the shift's statement of what it made. A recipe declaring a different batch size does not change that recorded output.
When a corrected recipe changes those borrowed component amounts, the shift has two ways to answer for a recorded session. It may stand behind the old quantities as its own measured facts; the session keeps its posting and the affected output's whole composition becomes the shift's rather than the recipe's. Or it may withdraw the posting and work from the corrected recipe. Then the whole session returns to a draft, with its recorded inputs, output and manually stated components preserved. Its new composition must balance, and any loss must be accepted again before the session is posted. Even a correction to one output withdraws the whole session, because its inputs and loss belong to the session as a whole. A closed session remains settled history.
For example, a session records 162 g of paste made using 600 g of tuna. Correcting the recipe's declared output from 162 g to 1,584 g does not prove the session made 1,584 g. At its recorded output, the corrected recipe accounts for only about 61.36 g of tuna. The remaining input needs an explanation: perhaps the recorded output was wrong, perhaps the composition was different, or perhaps there was a real loss. Only the shift can correct that fact; the recipe cannot choose for it.
That is why the loss above is honest rather than an artifact. If a resized batch quietly dragged a weighed amount along with it, the difference between the composition and the input would be arithmetic nobody performed. Because each amount stays with whoever last spoke for it, the difference is a fact about the shift.
Saving the material plan¶
A production calculation can be saved as a saved list when the operator wants to keep and edit its material requirements without turning them into a stock document. The calculation is run again from its production lines, and its aggregated planned item requirements become one ordered item section in canonical base units. Inputs, variance, and individual output-line detail do not enter the list; a line that would consume nothing does not produce a partial plan.
The result is an independent company-wide copy of the material plan. Editing it later does not change the production calculation, and changing the catalog does not rewrite the saved quantities, though every linked entry continues to open the current item it references. From there the operator may add labels, an overall note, attachments, free-text needs, or other typed sections without changing the calculation it came from. The list remains outside the ledger and outside procurement: it has no open, closed, or cancelled lifecycle, and even if a goods receipt later cites it as provenance, neither document consumes or changes the other.
Where a batch draws from — the production floor is a storage location¶
Recording a batch posts its stock ingredients out and its output in. Expensed ingredients remain in its physical composition without movements. The trade calls this backflushing — stock ingredients are deducted on the strength of the recorded output rather than issued by hand. It is forgiving by construction. Even a wrong recipe still yields correct books: the count-wins reconciliation absorbs the drift, and the variance report points at the recipe that caused it, so recipes can start rough and converge over a few close cycles.
The production floor determines where stock ingredients leave from. A warehouse holds its stock in one or more storage locations — the walk-in, the dry store, the kitchen table (see Scope & locations) — and every session names the one it worked on: its floor. The ingredients leave that floor and the yield lands back on it, because the batch was made there and that is where it stands when the shift ends. A draft that names no floor is simply an unfinished sheet — it may be saved and edited all day, but it cannot post, since a move-pair with no endpoint is not a fact anyone could later count against. And a floor is always a storage location of a warehouse that keeps operating stock: books that carry the asset register hold nothing to draw from and nothing to yield into.
Many sites name the very storage location they store from — the dry store is the prep bench, and the goods never travel. A site that has physically separated its prep gives that floor a storage location of its own, and the shift becomes an ordinary walk of goods:
shift opens relocate dry store → kitchen table raw goods walk over
day production run kitchen table → production ingredients, at pool cost
production → kitchen table the yield, same value
after service relocate kitchen table → dry store yield and unused raw walk back
end of shift count the kitchen table — usually all zeros, a clean table
Nothing here is a separate accounting regime. A relocation neither creates nor destroys value; the warehouse still prices its stock as one pool, so which storage location holds a kilo of flour never changes what that kilo is worth. The floor takes part in the period close like any other storage location — its own full count, its own differences — and the close will not run until it has been counted.
That makes the two kinds of error legible separately, which is the whole point of working this way. What the cooks actually used against what the recipe says they should have used is answered by the run's own facts: the session records the real ingredients, and a shift that has not been signed off sits in draft until somebody signs it. What quietly disappeared from the floor — a spill, a handful grabbed for staff food, a bag walked off — is answered by the floor's own count, as an ordinary shortage. It is shrinkage in one storage location, told apart from recipe error by where it surfaced, and it needs no special counterparty to say so.
9. Theoretical vs actual — what you should have used vs what you did¶
Recipes give you the theoretical side of food cost; physical counts give you the actual side. Comparing the two is one of the most valuable things an inventory system does, because the gap between them is where waste, over-portioning, and theft hide.
- Theoretical usage = for every made-to-order sale in the period, the sold item's portion quantity times its date-correct build explosion (§5) — the concrete build where the sale declares one, otherwise the base build. This is what should have been consumed for perfectly portioned plates with zero waste and zero loss, built entirely from recipes and sales.
- Actual usage = what the books say really left, derived from counts: opening balance + everything received + transfers in − closing count. This is the truth event of the period close (see Period close).
- Variance =
theoretical − actual, reported three ways: in quantity, in money, and as a percent. - Unexplained =
variance − logged waste. Once you subtract the waste someone actually recorded (a dropped tray, a spoiled batch), what's left is the operationally interesting residue — the over-portioning, the mis-invoicing, the shrink nobody wrote down.
Worked example. The recipes say a month of carrot-plate sales should have used 40 kg of whole carrots (theoretical). The count says 44 kg actually left (actual). Variance = −4 kg, roughly −€8 at €0.0020/g. Logged waste for the month was 1 kg (a spoiled crate). Unexplained = 3 kg — three kilos of carrots that left stock for no recorded reason. That's the number worth a manager's attention.
The recipe layer's whole job in this calculation is to make the theoretical term reproducible and date-correct — which is precisely what versioning (§2–§3) and pinned explosions (§5) buy you. The actual term comes from the count-and-close machinery in Period close. And the two only line up honestly if every sold made-to-order item had a recipe on its sale date — which is why such an item with no recipe in force is a hard close-blocker: it is held and surfaced for a human to fix — typically by writing the recipe and scheduling it back-dated to cover the sale dates (§3) — never silently exploded to zero cost (a made-to-order sale must never cost nothing).
10. When the recipe was wrong — repairing posted journals¶
Two recipe failures look alike and are nothing alike. A missing recipe already has its path: the sold lines are held until the operator writes the recipe and schedules it, pulling its effective date back to cover the sales (§3, §9). A produced session never waits on a recipe at all — it carries its own material plan, and a cook records the batch by writing what went into it. A wrong recipe is different: the lines did post, the books balanced — against the wrong explosion. Weeks later somebody notices the carbonara recipe said 30 g of guanciale when the cooks have always plated 45. What is on the books is not shrinkage; it is an error in posted journals, and it deserves a repair, not a shrug.
The repair is one edit, and it carries the books with it. When the wrong version's whole life lies in the open period, simply correct it in place — the fix re-explodes every sale that posted through it, on each sale's true business date, in the same stroke. When the error began further back, the schedule's own tools compose (§3): author the corrected version, unschedule the wrong one, move the corrected version onto its date — and again the affected open-period sales re-explode to the corrected answer as part of the move itself. Books and schedule cannot come to disagree by any of this: the edit and its consequences land together, or the whole edit refuses.
The repair reaches exactly as far back as the books are open. The schedule over sealed dates cannot move (§3), so a closed period's postings can never come to disagree with it: whatever a sealed period charged is settled — count-wins guaranteed the total was right, and the frozen facts stay frozen.
Worked example. The recipe said 30 g of guanciale; the cooks always plated 45. 200 plates sold in May through the wrong version, May still open. The operator corrects the recipe to 45 g — and that one edit re-explodes all 200 May sales on their true dates, consuming the missing
200 × 15 g = 3 kgof guanciale. The coming count no longer shows a 3 kg mystery, and nobody recorded anything twice.
11. One composition spine, four answers¶
A closing note on why the explosion is worth getting right beyond cost. Consumption, cost, nutrition, allergens, and the shelf-life safety cap all follow the same dated recipe structure, nesting rules, and yield facts. A single composition change marks every affected answer for refresh, so a made item cannot keep stale calories or allergens beside a current recipe.
The requested reading can differ without forking the structure. Consumption and cost may follow a concrete build; the canonical nutrition, allergen, and shelf-life statement of a matrix follows its base build. The prep item's output weight (§6) still does double duty as cost's divisor and nutrition's denominator. The food attributes are taught in their own chapter — Food attributes — but they remain one recipe graph, not a parallel composition model.
See also¶
- Sales & consumption — the sale that triggers the explosion, and the front door it comes through; where the unpacking stops at a stocked prep item.
- Period close — the period close and the actual side of theoretical-vs-actual variance this layer feeds.
- Stock ledger — the journal every consumption and production movement is recorded in; the never-edit-history discipline recipes share.
- Scope & locations — warehouses, restaurants, and the virtual production location the move-pair runs through.
- Item model & policies — what makes an item stocked and producible, the two facts that define a prep item.
- Catalog — items, product cards, recipes, and the "recipe actuality" rule (§3 here).
- Units of measure — base units, dimensions, and the convert-to-base edge the explosion crosses.
- Costing & valuation — the average cost each consumed ingredient is priced at, and how ingredient cost rolls into a produced batch.
- Food attributes — nutrition, allergens, and shelf-life as roll-ups on this same explosion.
- Glossary — recipe, recipe version, recipe actuality, prep item, EP/AP yield, and unit terms.