soustack 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/cli/index.js +4412 -1275
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +106 -80
- package/dist/index.d.ts +106 -80
- package/dist/index.js +4527 -1360
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4527 -1360
- package/dist/index.mjs.map +1 -1
- package/dist/scrape/index.d.mts +86 -74
- package/dist/scrape/index.d.ts +86 -74
- package/dist/scrape/index.js +91 -64
- package/dist/scrape/index.js.map +1 -1
- package/dist/scrape/index.mjs +91 -64
- package/dist/scrape/index.mjs.map +1 -1
- package/package.json +15 -6
- package/spec/.sync-meta.json +149 -0
- package/spec/SOUSTACK_SPEC_VERSION +1 -0
- package/spec/defs/common.schema.json +46 -0
- package/spec/defs/duration.schema.json +33 -0
- package/spec/defs/entities.schema.json +111 -0
- package/spec/defs/ingredientQuantified.schema.json +9 -0
- package/spec/defs/quantity.schema.json +16 -0
- package/spec/defs/scalingRule.schema.json +127 -0
- package/spec/defs/temperature.schema.json +63 -0
- package/spec/fixtures/content/illustrated-step.valid.json +24 -0
- package/spec/fixtures/invalid/equipment-unknown-reference.invalid.json +38 -0
- package/spec/fixtures/invalid/mise-en-place-unknown-equipment.invalid.json +37 -0
- package/spec/fixtures/invalid/mise-en-place-unknown-input.invalid.json +41 -0
- package/spec/fixtures/invalid/storage-leftovers-missing-method.invalid.json +31 -0
- package/spec/fixtures/invalid/storage-leftovers-wrong-type.invalid.json +23 -0
- package/spec/fixtures/level/base-full.valid.json +162 -0
- package/spec/fixtures/level/base-missing-yield.invalid.json +12 -0
- package/spec/fixtures/level/lite-min.valid.json +14 -0
- package/spec/fixtures/profile/profile-base.valid.json +20 -0
- package/spec/fixtures/profile/profile-equipped.valid.json +28 -0
- package/spec/fixtures/profile/profile-illustrated.valid.json +28 -0
- package/spec/fixtures/profile/profile-lite.valid.json +13 -0
- package/spec/fixtures/profile/profile-prepped.valid.json +31 -0
- package/spec/fixtures/profile/profile-scalable-missing-scaling.invalid.json +29 -0
- package/spec/fixtures/profile/profile-scalable.valid.json +49 -0
- package/spec/fixtures/profile/profile-timed-missing-structured.invalid.json +30 -0
- package/spec/fixtures/scaling/bakers-percent-missing-ref.invalid.json +41 -0
- package/spec/fixtures/scaling/bakers-percent.valid.json +51 -0
- package/spec/fixtures/scaling/discrete-range.invalid.json +36 -0
- package/spec/fixtures/scaling/missing-quantified.invalid.json +40 -0
- package/spec/fixtures/scaling/reject-bakersPercentage.invalid.json +50 -0
- package/spec/fixtures/stacks/compute-missing-timed.invalid.json +32 -0
- package/spec/fixtures/stacks/dietary-no-signal.invalid.json +16 -0
- package/spec/fixtures/stacks/illustrated-empty.invalid.json +13 -0
- package/spec/fixtures/stacks/quantified-string.invalid.json +22 -0
- package/spec/fixtures/stacks/referenced-missing-input.invalid.json +32 -0
- package/spec/fixtures/stacks/storage-min.valid.json +20 -0
- package/spec/fixtures/stacks/storage-no-duration.invalid.json +16 -0
- package/spec/fixtures/stacks/timed-implies-structured.valid.json +50 -0
- package/spec/fixtures/stacks/timed-range.invalid.json +33 -0
- package/spec/fixtures/valid/equipment-scaling-rules.valid.json +76 -0
- package/spec/fixtures/valid/equipment-strings.valid.json +31 -0
- package/spec/fixtures/valid/equipment-structured-uses.valid.json +47 -0
- package/spec/fixtures/valid/mise-en-place-basic.valid.json +31 -0
- package/spec/fixtures/valid/mise-en-place-referenced-equipment.valid.json +51 -0
- package/spec/fixtures/valid/prep-ingredient-strings.valid.json +48 -0
- package/spec/fixtures/valid/prep-ingredient-structured.valid.json +45 -0
- package/spec/fixtures/valid/profile-equipped.valid.json +29 -0
- package/spec/fixtures/valid/profile-prepped.valid.json +32 -0
- package/spec/fixtures/valid/quantified-nested-ingredient-sections.valid.json +61 -0
- package/spec/fixtures/valid/referenced-scaling.valid.json +67 -0
- package/spec/fixtures/valid/storage-leftovers-simple.valid.json +27 -0
- package/spec/fixtures/valid/storage-leftovers-structured.valid.json +43 -0
- package/spec/fixtures/valid/structured-nested-step-sections.valid.json +84 -0
- package/spec/schemas/stacks-registry.schema.json +108 -0
- package/spec/soustack.schema.json +2379 -0
- package/spec/stacks/compute.schema.json +7 -0
- package/spec/stacks/compute@1.md +22 -0
- package/spec/stacks/dietary.schema.json +45 -0
- package/spec/stacks/dietary@1.md +24 -0
- package/spec/stacks/equipment.schema.json +98 -0
- package/spec/stacks/equipment@1.md +244 -0
- package/spec/stacks/illustrated.schema.json +54 -0
- package/spec/stacks/illustrated@1.md +24 -0
- package/spec/stacks/prep.schema.json +76 -0
- package/spec/stacks/prep@1.md +276 -0
- package/spec/stacks/quantified.schema.json +74 -0
- package/spec/stacks/quantified@1.md +24 -0
- package/spec/stacks/referenced.schema.json +96 -0
- package/spec/stacks/referenced@1.md +23 -0
- package/spec/stacks/registry.json +112 -0
- package/spec/stacks/scaling.schema.json +99 -0
- package/spec/stacks/scaling@1.md +238 -0
- package/spec/stacks/storage.schema.json +132 -0
- package/spec/stacks/storage@1.md +256 -0
- package/spec/stacks/structured.schema.json +48 -0
- package/spec/stacks/structured@1.md +24 -0
- package/spec/stacks/substitutions.schema.json +43 -0
- package/spec/stacks/substitutions@1.md +24 -0
- package/spec/stacks/techniques.schema.json +28 -0
- package/spec/stacks/techniques@1.md +23 -0
- package/spec/stacks/timed.schema.json +60 -0
- package/spec/stacks/timed@1.md +23 -0
- package/src/defs/common.schema.json +46 -0
- package/src/defs/duration.schema.json +33 -0
- package/src/defs/entities.schema.json +111 -0
- package/src/defs/ingredientQuantified.schema.json +9 -0
- package/src/defs/quantity.schema.json +16 -0
- package/src/defs/scalingRule.schema.json +127 -0
- package/src/defs/temperature.schema.json +63 -0
- package/src/profiles/base.schema.json +2 -2
- package/src/profiles/equipped.schema.json +10 -0
- package/src/profiles/illustrated.schema.json +4 -4
- package/src/profiles/lite.schema.json +10 -0
- package/src/profiles/prepped.schema.json +10 -0
- package/src/profiles/scalable.schema.json +6 -6
- package/src/profiles/timed.schema.json +10 -0
- package/src/schema.json +2271 -248
- package/src/schemas/stacks-registry.schema.json +108 -0
- package/src/soustack.schema.json +2271 -248
- package/src/stacks/compute.schema.json +7 -0
- package/src/stacks/compute@1.md +22 -0
- package/src/stacks/dietary.schema.json +45 -0
- package/src/stacks/dietary@1.md +24 -0
- package/src/stacks/equipment.schema.json +98 -0
- package/src/stacks/equipment@1.md +244 -0
- package/src/stacks/illustrated.schema.json +54 -0
- package/src/stacks/illustrated@1.md +24 -0
- package/src/stacks/prep.schema.json +76 -0
- package/src/stacks/prep@1.md +276 -0
- package/src/stacks/quantified.schema.json +74 -0
- package/src/stacks/quantified@1.md +24 -0
- package/src/stacks/referenced.schema.json +96 -0
- package/src/stacks/referenced@1.md +23 -0
- package/src/stacks/registry.json +112 -0
- package/src/stacks/scaling.schema.json +99 -0
- package/src/stacks/scaling@1.md +238 -0
- package/src/stacks/storage.schema.json +132 -0
- package/src/stacks/storage@1.md +256 -0
- package/src/stacks/structured.schema.json +48 -0
- package/src/stacks/structured@1.md +24 -0
- package/src/stacks/substitutions.schema.json +43 -0
- package/src/stacks/substitutions@1.md +24 -0
- package/src/stacks/techniques.schema.json +28 -0
- package/src/stacks/techniques@1.md +23 -0
- package/src/stacks/timed.schema.json +60 -0
- package/src/stacks/timed@1.md +23 -0
- package/src/profiles/cookable.schema.json +0 -18
- package/src/profiles/quantified.schema.json +0 -43
- package/src/profiles/schedulable.schema.json +0 -43
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
#prep@1
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
The `prep@1` stack enables recipes to include preparation guidance at both the ingredient level and as explicit mise en place tasks. This makes recipes more operational by providing clear prep instructions and planning checklists.
|
|
8
|
+
|
|
9
|
+
This stack is adoption-first: ingredient prep can be simple strings for minimal friction, or structured objects for more detailed guidance.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
A document that declares `prep@1`:
|
|
16
|
+
|
|
17
|
+
• MUST satisfy all structural rules enabled by this stack.
|
|
18
|
+
• MUST satisfy the semantic rules described below.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Data Model
|
|
23
|
+
|
|
24
|
+
When `prep@1` is declared, the document MUST include a top-level `miseEnPlace` array.
|
|
25
|
+
|
|
26
|
+
### Mise En Place Array
|
|
27
|
+
|
|
28
|
+
The `miseEnPlace` array contains one or more tasks. Each task is a structured object that describes a prep step.
|
|
29
|
+
|
|
30
|
+
### Ingredient-Level Prep
|
|
31
|
+
|
|
32
|
+
Ingredient objects MAY include an optional `prep` field that describes how the ingredient should be prepared. The `prep` field supports multiple formats:
|
|
33
|
+
|
|
34
|
+
• A single string (simple prep phrase)
|
|
35
|
+
• An array of strings (multiple prep notes)
|
|
36
|
+
• An array of structured prep items
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Ingredient Prep Formats
|
|
41
|
+
|
|
42
|
+
### String Format
|
|
43
|
+
|
|
44
|
+
A simple string describing the prep:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"id": "onion",
|
|
49
|
+
"name": "Onion",
|
|
50
|
+
"prep": "finely diced"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Array of Strings
|
|
55
|
+
|
|
56
|
+
Multiple prep notes:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"id": "garlic",
|
|
61
|
+
"name": "Garlic",
|
|
62
|
+
"prep": ["peeled", "minced"]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Structured Prep Items
|
|
67
|
+
|
|
68
|
+
More detailed prep instructions with verbs and details:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"id": "tomato",
|
|
73
|
+
"name": "Tomato",
|
|
74
|
+
"prep": [
|
|
75
|
+
{ "verb": "dice", "detail": "fine" },
|
|
76
|
+
{ "verb": "reserve", "detail": "half for garnish" }
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Each prep item object includes:
|
|
82
|
+
|
|
83
|
+
• `verb` (required): string describing the action (freeform; no controlled vocabulary in v1)
|
|
84
|
+
• `detail` (optional): string providing additional context
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Mise En Place Tasks
|
|
89
|
+
|
|
90
|
+
### Minimal Task
|
|
91
|
+
|
|
92
|
+
A task with only required text:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"miseEnPlace": [
|
|
97
|
+
{ "text": "Finely dice the onion" },
|
|
98
|
+
{ "text": "Mince the garlic" }
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Task with ID
|
|
104
|
+
|
|
105
|
+
Tasks may include an optional `id` for cross-referencing:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"miseEnPlace": [
|
|
110
|
+
{ "id": "dice-onion", "text": "Finely dice the onion" },
|
|
111
|
+
{ "id": "mince-garlic", "text": "Mince the garlic" }
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Task IDs MUST be unique within the `miseEnPlace` array (semantic validation).
|
|
117
|
+
|
|
118
|
+
### Task with Ingredient References
|
|
119
|
+
|
|
120
|
+
When `referenced@1` is present, tasks may reference ingredient IDs:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"miseEnPlace": [
|
|
125
|
+
{
|
|
126
|
+
"text": "Prepare the vegetables",
|
|
127
|
+
"inputs": ["onion", "garlic"]
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Each id in `inputs` MUST exist in the ingredients array (semantic validation when both stacks are present).
|
|
134
|
+
|
|
135
|
+
### Task with Equipment References
|
|
136
|
+
|
|
137
|
+
When `equipment@1` is present, tasks may reference equipment IDs:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{
|
|
141
|
+
"miseEnPlace": [
|
|
142
|
+
{
|
|
143
|
+
"text": "Sharpen the knife",
|
|
144
|
+
"usesEquipment": ["knife"]
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Each id in `usesEquipment` MUST exist in the equipment array (semantic validation when both stacks are present).
|
|
151
|
+
|
|
152
|
+
### Combined References
|
|
153
|
+
|
|
154
|
+
Tasks may include both `inputs` and `usesEquipment`:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"miseEnPlace": [
|
|
159
|
+
{
|
|
160
|
+
"text": "Dice the onion with a sharp knife",
|
|
161
|
+
"inputs": ["onion"],
|
|
162
|
+
"usesEquipment": ["knife"]
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Semantics
|
|
171
|
+
|
|
172
|
+
### Prep Field
|
|
173
|
+
|
|
174
|
+
The ingredient `prep` field is descriptive and freeform. In v1, there is no controlled vocabulary for prep verbs or details. Tools may interpret these as hints for display or planning, but validation does not enforce specific values.
|
|
175
|
+
|
|
176
|
+
### Mise En Place
|
|
177
|
+
|
|
178
|
+
The `miseEnPlace` array is an explicit checklist of prep tasks. Tools may render this as a prep plan, separate from the main cooking instructions. Tasks are ordered and may be presented as a sequential checklist.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Composition
|
|
183
|
+
|
|
184
|
+
The prep stack is composable with other stacks:
|
|
185
|
+
|
|
186
|
+
• No hard dependency on `referenced@1` or `equipment@1` (references are optional and only validated when those stacks are present)
|
|
187
|
+
• Works with `structured@1` to enable ingredient object definitions
|
|
188
|
+
• Remains monotonic: does not close objects needed by other stacks
|
|
189
|
+
• Ingredient `prep` is optional even when the stack is present
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Semantic Validation Rules (Normative)
|
|
194
|
+
|
|
195
|
+
Validators MUST enforce the following rules:
|
|
196
|
+
|
|
197
|
+
1. Mise en place task ID uniqueness
|
|
198
|
+
If tasks include `id` values, all task IDs MUST be unique within the `miseEnPlace` array.
|
|
199
|
+
|
|
200
|
+
2. Ingredient reference resolution
|
|
201
|
+
If both `prep@1` and `referenced@1` are present, and a task includes `inputs`, all referenced ingredient IDs MUST exist in the ingredients array.
|
|
202
|
+
|
|
203
|
+
3. Equipment reference resolution
|
|
204
|
+
If both `prep@1` and `equipment@1` are present, and a task includes `usesEquipment`, all referenced equipment IDs MUST exist in the equipment array (as object ids, not string items).
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Examples
|
|
209
|
+
|
|
210
|
+
Minimal mise en place
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"miseEnPlace": [
|
|
215
|
+
{ "text": "Finely dice the onion" },
|
|
216
|
+
{ "text": "Mince the garlic" }
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Ingredient prep with strings
|
|
222
|
+
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"ingredients": [
|
|
226
|
+
{
|
|
227
|
+
"id": "onion",
|
|
228
|
+
"name": "Onion",
|
|
229
|
+
"prep": "finely diced"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"id": "garlic",
|
|
233
|
+
"name": "Garlic",
|
|
234
|
+
"prep": ["peeled", "minced"]
|
|
235
|
+
}
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Structured prep items
|
|
241
|
+
|
|
242
|
+
```json
|
|
243
|
+
{
|
|
244
|
+
"ingredients": [
|
|
245
|
+
{
|
|
246
|
+
"id": "tomato",
|
|
247
|
+
"name": "Tomato",
|
|
248
|
+
"prep": [
|
|
249
|
+
{ "verb": "dice", "detail": "fine" },
|
|
250
|
+
{ "verb": "reserve", "detail": "half for garnish" }
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
]
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Mise en place with references
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"equipment": [
|
|
262
|
+
{ "id": "knife", "name": "Chef's knife" }
|
|
263
|
+
],
|
|
264
|
+
"ingredients": [
|
|
265
|
+
{ "id": "onion", "name": "Onion" }
|
|
266
|
+
],
|
|
267
|
+
"miseEnPlace": [
|
|
268
|
+
{
|
|
269
|
+
"text": "Dice the onion with a sharp knife",
|
|
270
|
+
"inputs": ["onion"],
|
|
271
|
+
"usesEquipment": ["knife"]
|
|
272
|
+
}
|
|
273
|
+
]
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://soustack.spec/stacks/quantified.schema.json",
|
|
4
|
+
"title": "Quantified Stack",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"ingredients": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"items": {
|
|
10
|
+
"anyOf": [
|
|
11
|
+
{ "$ref": "#/$defs/ingredient" },
|
|
12
|
+
{ "$ref": "#/$defs/ingredientSection" }
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"required": ["ingredients"],
|
|
18
|
+
"$defs": {
|
|
19
|
+
"ingredient": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"properties": {
|
|
22
|
+
"id": { "type": "string" },
|
|
23
|
+
"name": { "type": "string" },
|
|
24
|
+
"quantity": { "$ref": "../defs/quantity.schema.json" },
|
|
25
|
+
"temperature": { "$ref": "../defs/temperature.schema.json" },
|
|
26
|
+
"notes": { "type": "string" },
|
|
27
|
+
"prep": {
|
|
28
|
+
"oneOf": [
|
|
29
|
+
{ "type": "string", "minLength": 1 },
|
|
30
|
+
{
|
|
31
|
+
"type": "array",
|
|
32
|
+
"minItems": 1,
|
|
33
|
+
"items": {
|
|
34
|
+
"anyOf": [
|
|
35
|
+
{ "type": "string", "minLength": 1 },
|
|
36
|
+
{ "$ref": "../stacks/prep.schema.json#/$defs/prepItem" }
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"metadata": { "type": "object", "additionalProperties": true },
|
|
43
|
+
"scaling": { "$ref": "../defs/scalingRule.schema.json" }
|
|
44
|
+
},
|
|
45
|
+
"required": ["id", "name", "quantity"],
|
|
46
|
+
"additionalProperties": false,
|
|
47
|
+
"patternProperties": {
|
|
48
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"ingredientSection": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"properties": {
|
|
54
|
+
"section": { "type": "string" },
|
|
55
|
+
"ingredients": {
|
|
56
|
+
"type": "array",
|
|
57
|
+
"items": {
|
|
58
|
+
"anyOf": [
|
|
59
|
+
{ "$ref": "#/$defs/ingredient" },
|
|
60
|
+
{ "$ref": "#/$defs/ingredientSection" }
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"metadata": { "type": "object", "additionalProperties": true }
|
|
65
|
+
},
|
|
66
|
+
"required": ["section", "ingredients"],
|
|
67
|
+
"additionalProperties": false,
|
|
68
|
+
"patternProperties": {
|
|
69
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"additionalProperties": false
|
|
74
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# quantified@1
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
The `quantified@1` stack enables recipes to declare precise ingredient quantities with units, enabling scaling and computation.
|
|
5
|
+
|
|
6
|
+
## Adds
|
|
7
|
+
- Top-level `ingredients` array with structured ingredient objects containing `id`, `name`, and `quantity` fields.
|
|
8
|
+
- Ingredients may include `temperature`, `notes`, `prep`, `scaling`, and `metadata`.
|
|
9
|
+
- Support for nested ingredient sections.
|
|
10
|
+
|
|
11
|
+
## Requires
|
|
12
|
+
- None
|
|
13
|
+
|
|
14
|
+
## Semantics
|
|
15
|
+
- MUST: Each ingredient object must include `id`, `name`, and `quantity` fields.
|
|
16
|
+
- MUST: Ingredient IDs must be unique within the ingredients array.
|
|
17
|
+
- NOTE: This stack is a prerequisite for `scaling@1`.
|
|
18
|
+
|
|
19
|
+
## Composition Notes
|
|
20
|
+
- This stack is monotonic: it adds requirements or fields without removing expressiveness.
|
|
21
|
+
- Interaction: Required by `scaling@1` for scaling behavior. Works with `structured@1` for stable ingredient references.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://soustack.spec/stacks/referenced.schema.json",
|
|
4
|
+
"title": "Referenced Stack",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"ingredients": {
|
|
8
|
+
"type": "array",
|
|
9
|
+
"items": {
|
|
10
|
+
"anyOf": [
|
|
11
|
+
{ "$ref": "#/$defs/ingredient" },
|
|
12
|
+
{ "$ref": "#/$defs/ingredientSection" }
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"instructions": {
|
|
17
|
+
"type": "array",
|
|
18
|
+
"items": {
|
|
19
|
+
"anyOf": [
|
|
20
|
+
{ "$ref": "#/$defs/referencedStep" },
|
|
21
|
+
{ "$ref": "#/$defs/referencedSection" }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"required": ["ingredients", "instructions"],
|
|
27
|
+
"allOf": [
|
|
28
|
+
{ "$ref": "./structured.schema.json" }
|
|
29
|
+
],
|
|
30
|
+
"$defs": {
|
|
31
|
+
"ingredient": {
|
|
32
|
+
"allOf": [
|
|
33
|
+
{ "$ref": "../defs/entities.schema.json#/$defs/IngredientBase" },
|
|
34
|
+
{ "required": ["id"] }
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"ingredientSection": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"properties": {
|
|
40
|
+
"section": { "type": "string" },
|
|
41
|
+
"ingredients": {
|
|
42
|
+
"type": "array",
|
|
43
|
+
"items": {
|
|
44
|
+
"anyOf": [
|
|
45
|
+
{ "$ref": "#/$defs/ingredient" },
|
|
46
|
+
{ "$ref": "#/$defs/ingredientSection" }
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"metadata": { "type": "object", "additionalProperties": true }
|
|
51
|
+
},
|
|
52
|
+
"required": ["section", "ingredients"],
|
|
53
|
+
"additionalProperties": false,
|
|
54
|
+
"patternProperties": {
|
|
55
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"referencedStep": {
|
|
59
|
+
"allOf": [
|
|
60
|
+
{ "$ref": "../defs/entities.schema.json#/$defs/StepBase" },
|
|
61
|
+
{
|
|
62
|
+
"properties": {
|
|
63
|
+
"inputs": {
|
|
64
|
+
"allOf": [
|
|
65
|
+
{ "$ref": "../defs/entities.schema.json#/$defs/StepBase/properties/inputs" },
|
|
66
|
+
{ "minItems": 1 }
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"required": ["id", "inputs"]
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
"referencedSection": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"properties": {
|
|
77
|
+
"section": { "type": "string" },
|
|
78
|
+
"steps": {
|
|
79
|
+
"type": "array",
|
|
80
|
+
"items": {
|
|
81
|
+
"anyOf": [
|
|
82
|
+
{ "$ref": "#/$defs/referencedStep" },
|
|
83
|
+
{ "$ref": "#/$defs/referencedSection" }
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"metadata": { "type": "object", "additionalProperties": true }
|
|
88
|
+
},
|
|
89
|
+
"required": ["section", "steps"],
|
|
90
|
+
"additionalProperties": false,
|
|
91
|
+
"patternProperties": {
|
|
92
|
+
"^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# referenced@1
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
The `referenced@1` stack enables steps to explicitly reference ingredient IDs, creating clear input-output relationships for planning and validation.
|
|
5
|
+
|
|
6
|
+
## Adds
|
|
7
|
+
- Step objects must include an `inputs` array with at least one ingredient ID reference.
|
|
8
|
+
- Ingredient objects must include `id` fields.
|
|
9
|
+
|
|
10
|
+
## Requires
|
|
11
|
+
- `structured@1`
|
|
12
|
+
|
|
13
|
+
## Semantics
|
|
14
|
+
- MUST: Each step must include an `inputs` array with at least one element.
|
|
15
|
+
- MUST: All ingredient IDs referenced in step `inputs` must exist in the ingredients array.
|
|
16
|
+
- NOTE: This stack implies `structured@1` (steps are objects with IDs).
|
|
17
|
+
|
|
18
|
+
## Composition Notes
|
|
19
|
+
- This stack is monotonic: it adds requirements or fields without removing expressiveness.
|
|
20
|
+
- Interaction: Required by `substitutions@1` for substitution target resolution. Works with `prep@1` for mise en place task references.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../schemas/stacks-registry.schema.json",
|
|
3
|
+
"registryVersion": 1,
|
|
4
|
+
"spec": {
|
|
5
|
+
"name": "soustack",
|
|
6
|
+
"currentSpecVersion": "0.3.0",
|
|
7
|
+
"canonicalStacksFormat": "map"
|
|
8
|
+
},
|
|
9
|
+
"profiles": {
|
|
10
|
+
"lite": { "title": "Lite", "description": "Lowest-friction publishing with minimal structure", "requiresProfiles": [], "requiresStacks": [] },
|
|
11
|
+
"base": { "title": "Base", "description": "Minimum cookable baseline with yield + time", "requiresProfiles": ["lite"], "requiresStacks": [] },
|
|
12
|
+
"scalable": { "title": "Scalable", "description": "Quantified + scaling", "requiresProfiles": ["base"], "requiresStacks": ["quantified", "scaling"] },
|
|
13
|
+
"timed": { "title": "Timed", "description": "Structured + timed", "requiresProfiles": ["base"], "requiresStacks": ["structured", "timed"] },
|
|
14
|
+
"illustrated": { "title": "Illustrated", "description": "Media present", "requiresProfiles": ["base"], "requiresStacks": ["illustrated"] },
|
|
15
|
+
"equipped": { "title": "Equipped", "description": "Recipe declares required tools/equipment.", "requiresProfiles": ["base"], "requiresStacks": ["equipment"] },
|
|
16
|
+
"prepped": { "title": "Prepped", "description": "Recipe includes prep guidance and/or mise en place tasks.", "requiresProfiles": ["base"], "requiresStacks": ["prep"] }
|
|
17
|
+
},
|
|
18
|
+
"stacks": {
|
|
19
|
+
"quantified": {
|
|
20
|
+
"title": "Quantified",
|
|
21
|
+
"latestMajor": 1,
|
|
22
|
+
"requires": [],
|
|
23
|
+
"schema": { "major": { "1": "stacks/quantified.schema.json" } },
|
|
24
|
+
"docs": { "major": { "1": "stacks/quantified@1.md" } }
|
|
25
|
+
},
|
|
26
|
+
"scaling": {
|
|
27
|
+
"title": "Scaling",
|
|
28
|
+
"latestMajor": 1,
|
|
29
|
+
"requires": ["quantified"],
|
|
30
|
+
"schema": { "major": { "1": "stacks/scaling.schema.json" } },
|
|
31
|
+
"docs": { "major": { "1": "stacks/scaling@1.md" } }
|
|
32
|
+
},
|
|
33
|
+
"structured": {
|
|
34
|
+
"title": "Structured",
|
|
35
|
+
"latestMajor": 1,
|
|
36
|
+
"requires": [],
|
|
37
|
+
"schema": { "major": { "1": "stacks/structured.schema.json" } },
|
|
38
|
+
"docs": { "major": { "1": "stacks/structured@1.md" } }
|
|
39
|
+
},
|
|
40
|
+
"timed": {
|
|
41
|
+
"title": "Timed",
|
|
42
|
+
"latestMajor": 1,
|
|
43
|
+
"requires": ["structured"],
|
|
44
|
+
"schema": { "major": { "1": "stacks/timed.schema.json" } },
|
|
45
|
+
"docs": { "major": { "1": "stacks/timed@1.md" } }
|
|
46
|
+
},
|
|
47
|
+
"referenced": {
|
|
48
|
+
"title": "Referenced",
|
|
49
|
+
"latestMajor": 1,
|
|
50
|
+
"requires": ["structured"],
|
|
51
|
+
"schema": { "major": { "1": "stacks/referenced.schema.json" } },
|
|
52
|
+
"docs": { "major": { "1": "stacks/referenced@1.md" } }
|
|
53
|
+
},
|
|
54
|
+
"illustrated": {
|
|
55
|
+
"title": "Illustrated",
|
|
56
|
+
"latestMajor": 1,
|
|
57
|
+
"requires": [],
|
|
58
|
+
"schema": { "major": { "1": "stacks/illustrated.schema.json" } },
|
|
59
|
+
"docs": { "major": { "1": "stacks/illustrated@1.md" } }
|
|
60
|
+
},
|
|
61
|
+
"dietary": {
|
|
62
|
+
"title": "Dietary",
|
|
63
|
+
"latestMajor": 1,
|
|
64
|
+
"requires": [],
|
|
65
|
+
"schema": { "major": { "1": "stacks/dietary.schema.json" } },
|
|
66
|
+
"docs": { "major": { "1": "stacks/dietary@1.md" } }
|
|
67
|
+
},
|
|
68
|
+
"substitutions": {
|
|
69
|
+
"title": "Substitutions",
|
|
70
|
+
"latestMajor": 1,
|
|
71
|
+
"requires": ["referenced"],
|
|
72
|
+
"schema": { "major": { "1": "stacks/substitutions.schema.json" } },
|
|
73
|
+
"docs": { "major": { "1": "stacks/substitutions@1.md" } }
|
|
74
|
+
},
|
|
75
|
+
"techniques": {
|
|
76
|
+
"title": "Techniques",
|
|
77
|
+
"latestMajor": 1,
|
|
78
|
+
"requires": [],
|
|
79
|
+
"schema": { "major": { "1": "stacks/techniques.schema.json" } },
|
|
80
|
+
"docs": { "major": { "1": "stacks/techniques@1.md" } }
|
|
81
|
+
},
|
|
82
|
+
"storage": {
|
|
83
|
+
"title": "Storage",
|
|
84
|
+
"latestMajor": 1,
|
|
85
|
+
"requires": [],
|
|
86
|
+
"schema": { "major": { "1": "stacks/storage.schema.json" } },
|
|
87
|
+
"docs": { "major": { "1": "stacks/storage@1.md" } }
|
|
88
|
+
},
|
|
89
|
+
"compute": {
|
|
90
|
+
"title": "Compute",
|
|
91
|
+
"latestMajor": 1,
|
|
92
|
+
"requires": ["quantified", "timed"],
|
|
93
|
+
"schema": { "major": { "1": "stacks/compute.schema.json" } },
|
|
94
|
+
"docs": { "major": { "1": "stacks/compute@1.md" } }
|
|
95
|
+
},
|
|
96
|
+
"equipment": {
|
|
97
|
+
"title": "Equipment",
|
|
98
|
+
"latestMajor": 1,
|
|
99
|
+
"requires": [],
|
|
100
|
+
"schema": { "major": { "1": "stacks/equipment.schema.json" } },
|
|
101
|
+
"docs": { "major": { "1": "stacks/equipment@1.md" } }
|
|
102
|
+
},
|
|
103
|
+
"prep": {
|
|
104
|
+
"title": "Prep",
|
|
105
|
+
"latestMajor": 1,
|
|
106
|
+
"requires": [],
|
|
107
|
+
"schema": { "major": { "1": "stacks/prep.schema.json" } },
|
|
108
|
+
"docs": { "major": { "1": "stacks/prep@1.md" } }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|