Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions docs/core-model.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S

== Purpose

RPF describes a recipe as a directed acyclic graph (DAG) of material transformations.
RPF describes a recipe as a Directed Acyclic Graph (DAG) of material transformations.

This model defines the smallest set of concepts needed to describe how externally introduced materials are transformed into resulting process states. It describes material transformations through process states; it does not describe workflow execution.
This model defines the smallest set of concepts needed to describe how externally introduced materials are transformed into resulting process states. It describes material transformations through process states, rather than workflow execution.

== Design Principles

Expand Down Expand Up @@ -44,13 +44,13 @@ Operations are the only mechanism by which the process changes.

=== State

A State is the result of an Operation and represents a coherent work product at a particular stage of the process.
A State is the result of an Operation and represents a coherent material condition at a particular point in the process.

A State SHALL be produced by exactly one Operation and SHALL be immutable. A State MAY be consumed by multiple Operations.
A State SHALL be produced by exactly one Operation and SHALL be immutable. Its material condition SHALL NOT be modified. A changed material condition SHALL be represented by a distinct State produced by an Operation. A State MAY be consumed by multiple Operations.

== Process Graph

A recipe SHALL be represented as a directed acyclic graph. Its nodes are Ingredients, Operations, and States. Its directed relationships express consumption and production.
A recipe SHALL be represented as a Directed Acyclic Graph (DAG). Its nodes are Ingredients, Operations, and States. Directed relationships from Ingredients or States to Operations express consumption; directed relationships from Operations to States express production.

[source,text]
----
Expand All @@ -61,7 +61,7 @@ An Operation consumes its input Ingredients and/or States and produces its one r

The graph SHALL be acyclic: no sequence of directed relationships MAY return to a prior node.

A State MAY be reused as an input to more than one Operation.
The same immutable State MAY be consumed by more than one Operation.

[source,text]
----
Expand All @@ -72,15 +72,15 @@ State ----------<

== Process States

Every meaningful process transition SHALL be represented by an Operation and its resulting State.
Every meaningful process transition SHALL be represented by an Operation and its resulting State. A later material condition SHALL NOT be represented by modifying an existing State.

Passive transformations, including Rest, Cool, Rise, Marinate, Freeze, and Thaw, are ordinary Operations. They have no special processing rules.

== Quantities

Quantities belong to the consumption relationship between an Ingredient or State and an Operation.
When a quantity is expressed, it SHALL belong to the consumption relationship between an Ingredient or State and an Operation.

A State does not itself define how much of it is consumed by an Operation.
An Ingredient or State does not itself define how much of it is consumed by an Operation.

== Invariants

Expand All @@ -90,12 +90,13 @@ Every valid RPF recipe SHALL satisfy all of the following invariants.
. Every State SHALL be produced by exactly one Operation.
. Ingredients SHALL NOT have producing Operations.
. States SHALL be immutable.
. A changed material condition SHALL be represented by a distinct State produced by an Operation.
. A State MAY be consumed by multiple Operations.
. Every meaningful process transition SHALL be represented by an Operation.
. The process graph SHALL be acyclic.

== Out of Scope

The core model does not define concrete representations, rendering, user interfaces, execution engines, or AI-assisted recipe generation.
The core model does not define concrete representations, rendering, user interfaces, workflow execution, scheduling, execution engines, or AI-assisted recipe generation.

Those concerns are outside the conceptual foundation defined by this document.
29 changes: 29 additions & 0 deletions examples/creamy-tofu-broccoli/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
= Creamy Tofu and Broccoli in Sesame and Miso Sauce

This example models the complete four-serving recipe provided in `Kramig_tofu_och_broccoli_i_sesam_och_misosas_A4.pdf`. It was chosen because tofu, vegetables, sauce, rice, and garnish follow independent preparation paths before they converge in the finished dish.

== What This Example Validates

The example demonstrates that the RPF Core Model can describe a complete recipe using only Ingredients, Operations, and States.

- Every meaningful transformation is represented by an Operation.
- Every Operation produces one immutable State.
- Each State has one producing Operation.
- The independent tofu, vegetable, sauce, rice, and garnish paths form a Directed Acyclic Graph.
- Quantities occur only on consumption entries, never on a State.
- No workflow, scheduling, equipment, or execution concepts are required.

`recipe.rpf.yaml` is an experimental design artefact. It is not a proposed serialization format. Its purpose is readability and a faithful representation of the Core Model.

== Modelling Challenges

The source recipe gives alternatives for mushrooms and for tahini or peanut butter. These are represented as alternative Ingredient choices, rather than as new conceptual entities. The source also leaves rice and garnish quantities open; the corresponding consumption relationships therefore use `as needed` or `to taste`.

The recipe directs the cook to set fried tofu aside, then add it back to the simmered sauce. This is naturally represented as an immutable fried-tofu State consumed later by the final simmering Operation. The recipe does not require a State to be consumed by more than one Operation, but the Core Model permits that when a recipe needs it.

No additional core concepts appeared necessary. By-products, cooking time, cookware, heat source, and serving order are useful information, but they are not necessary to express the recipe's material transformations and are intentionally not modelled.

== Files

- `recipe.rpf.yaml` is the readable experimental graph.
- `graph.mmd` is the Mermaid rendering of the same Ingredient-Operation-State graph.
63 changes: 63 additions & 0 deletions examples/creamy-tofu-broccoli/graph.mmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
flowchart TD
tofu["Ingredient: firm tofu"] --> press(["Operation: press tofu"])
press --> pressed[["State: pressed tofu"]]
pressed --> cutTofu(["Operation: cut tofu"])
cutTofu --> cubed[["State: cubed tofu"]]
cubed --> coat(["Operation: coat tofu"])
cornstarch["Ingredient: cornstarch"] --> coat
coat --> coated[["State: coated tofu"]]
coated --> fryTofu(["Operation: fry tofu"])
rapeseedOil["Ingredient: rapeseed oil"] --> fryTofu
fryTofu --> friedTofu[["State: fried tofu"]]

broccoli["Ingredient: broccoli"] --> cutBroccoli(["Operation: cut broccoli"])
cutBroccoli --> broccoliFlorets[["State: broccoli florets"]]
mushrooms["Ingredient: mushrooms"] --> sliceMushrooms(["Operation: slice mushrooms"])
sliceMushrooms --> slicedMushrooms[["State: sliced mushrooms"]]
onion["Ingredient: yellow onion"] --> sliceOnion(["Operation: slice onion"])
sliceOnion --> slicedOnion[["State: sliced onion"]]
garlic["Ingredient: garlic"] --> chopGarlic(["Operation: chop garlic"])
chopGarlic --> choppedGarlic[["State: chopped garlic"]]
ginger["Ingredient: fresh ginger"] --> grateGinger(["Operation: grate ginger"])
grateGinger --> gratedGinger[["State: grated ginger"]]
slicedOnion --> saute(["Operation: saute aromatics and mushrooms"])
slicedMushrooms --> saute
choppedGarlic --> saute
gratedGinger --> saute
saute --> sauteed[["State: sauteed aromatics and mushrooms"]]
broccoliFlorets --> fryVegetables(["Operation: fry broccoli with vegetables"])
sauteed --> fryVegetables
fryVegetables --> friedVegetables[["State: fried vegetables"]]

cream["Ingredient: cooking cream"] --> mixSauce(["Operation: mix cream, sesame, and miso sauce"])
stock["Ingredient: vegetable stock"] --> mixSauce
miso["Ingredient: white miso"] --> mixSauce
soy["Ingredient: Japanese soy sauce"] --> mixSauce
tahini["Ingredient: tahini or peanut butter"] --> mixSauce
mirin["Ingredient: mirin"] --> mixSauce
sesameOil["Ingredient: sesame oil"] --> mixSauce
vinegar["Ingredient: rice vinegar"] --> mixSauce
honey["Ingredient: honey"] --> mixSauce
cornstarch --> mixSauce
coldWater["Ingredient: cold water"] --> mixSauce
mixSauce --> mixedSauce[["State: mixed cream, sesame, and miso sauce"]]
friedVegetables --> combineSauce(["Operation: combine vegetables and sauce"])
mixedSauce --> combineSauce
combineSauce --> vegetablesInSauce[["State: vegetables in sauce"]]
vegetablesInSauce --> simmerVegetables(["Operation: simmer vegetables in sauce"])
simmerVegetables --> simmeredVegetables[["State: simmered vegetables in sauce"]]
friedTofu --> simmerTofu(["Operation: simmer tofu in sauce"])
simmeredVegetables --> simmerTofu
simmerTofu --> tofuBroccoliSauce[["State: tofu and broccoli in sesame and miso sauce"]]

rice["Ingredient: jasmine rice"] --> cookRice(["Operation: cook jasmine rice"])
water["Ingredient: water"] --> cookRice
cookRice --> cookedRice[["State: cooked jasmine rice"]]
springOnion["Ingredient: spring onion"] --> sliceSpringOnion(["Operation: slice spring onion"])
sliceSpringOnion --> slicedSpringOnion[["State: sliced spring onion"]]

cookedRice --> assemble(["Operation: assemble dish"])
tofuBroccoliSauce --> assemble
sesameSeeds["Ingredient: toasted sesame seeds"] --> assemble
slicedSpringOnion --> assemble
assemble --> finished[["State: creamy tofu and broccoli dish"]]
Loading
Loading