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.
Files changed (146) hide show
  1. package/README.md +4 -4
  2. package/dist/cli/index.js +4412 -1275
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/index.d.mts +106 -80
  5. package/dist/index.d.ts +106 -80
  6. package/dist/index.js +4527 -1360
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +4527 -1360
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/scrape/index.d.mts +86 -74
  11. package/dist/scrape/index.d.ts +86 -74
  12. package/dist/scrape/index.js +91 -64
  13. package/dist/scrape/index.js.map +1 -1
  14. package/dist/scrape/index.mjs +91 -64
  15. package/dist/scrape/index.mjs.map +1 -1
  16. package/package.json +15 -6
  17. package/spec/.sync-meta.json +149 -0
  18. package/spec/SOUSTACK_SPEC_VERSION +1 -0
  19. package/spec/defs/common.schema.json +46 -0
  20. package/spec/defs/duration.schema.json +33 -0
  21. package/spec/defs/entities.schema.json +111 -0
  22. package/spec/defs/ingredientQuantified.schema.json +9 -0
  23. package/spec/defs/quantity.schema.json +16 -0
  24. package/spec/defs/scalingRule.schema.json +127 -0
  25. package/spec/defs/temperature.schema.json +63 -0
  26. package/spec/fixtures/content/illustrated-step.valid.json +24 -0
  27. package/spec/fixtures/invalid/equipment-unknown-reference.invalid.json +38 -0
  28. package/spec/fixtures/invalid/mise-en-place-unknown-equipment.invalid.json +37 -0
  29. package/spec/fixtures/invalid/mise-en-place-unknown-input.invalid.json +41 -0
  30. package/spec/fixtures/invalid/storage-leftovers-missing-method.invalid.json +31 -0
  31. package/spec/fixtures/invalid/storage-leftovers-wrong-type.invalid.json +23 -0
  32. package/spec/fixtures/level/base-full.valid.json +162 -0
  33. package/spec/fixtures/level/base-missing-yield.invalid.json +12 -0
  34. package/spec/fixtures/level/lite-min.valid.json +14 -0
  35. package/spec/fixtures/profile/profile-base.valid.json +20 -0
  36. package/spec/fixtures/profile/profile-equipped.valid.json +28 -0
  37. package/spec/fixtures/profile/profile-illustrated.valid.json +28 -0
  38. package/spec/fixtures/profile/profile-lite.valid.json +13 -0
  39. package/spec/fixtures/profile/profile-prepped.valid.json +31 -0
  40. package/spec/fixtures/profile/profile-scalable-missing-scaling.invalid.json +29 -0
  41. package/spec/fixtures/profile/profile-scalable.valid.json +49 -0
  42. package/spec/fixtures/profile/profile-timed-missing-structured.invalid.json +30 -0
  43. package/spec/fixtures/scaling/bakers-percent-missing-ref.invalid.json +41 -0
  44. package/spec/fixtures/scaling/bakers-percent.valid.json +51 -0
  45. package/spec/fixtures/scaling/discrete-range.invalid.json +36 -0
  46. package/spec/fixtures/scaling/missing-quantified.invalid.json +40 -0
  47. package/spec/fixtures/scaling/reject-bakersPercentage.invalid.json +50 -0
  48. package/spec/fixtures/stacks/compute-missing-timed.invalid.json +32 -0
  49. package/spec/fixtures/stacks/dietary-no-signal.invalid.json +16 -0
  50. package/spec/fixtures/stacks/illustrated-empty.invalid.json +13 -0
  51. package/spec/fixtures/stacks/quantified-string.invalid.json +22 -0
  52. package/spec/fixtures/stacks/referenced-missing-input.invalid.json +32 -0
  53. package/spec/fixtures/stacks/storage-min.valid.json +20 -0
  54. package/spec/fixtures/stacks/storage-no-duration.invalid.json +16 -0
  55. package/spec/fixtures/stacks/timed-implies-structured.valid.json +50 -0
  56. package/spec/fixtures/stacks/timed-range.invalid.json +33 -0
  57. package/spec/fixtures/valid/equipment-scaling-rules.valid.json +76 -0
  58. package/spec/fixtures/valid/equipment-strings.valid.json +31 -0
  59. package/spec/fixtures/valid/equipment-structured-uses.valid.json +47 -0
  60. package/spec/fixtures/valid/mise-en-place-basic.valid.json +31 -0
  61. package/spec/fixtures/valid/mise-en-place-referenced-equipment.valid.json +51 -0
  62. package/spec/fixtures/valid/prep-ingredient-strings.valid.json +48 -0
  63. package/spec/fixtures/valid/prep-ingredient-structured.valid.json +45 -0
  64. package/spec/fixtures/valid/profile-equipped.valid.json +29 -0
  65. package/spec/fixtures/valid/profile-prepped.valid.json +32 -0
  66. package/spec/fixtures/valid/quantified-nested-ingredient-sections.valid.json +61 -0
  67. package/spec/fixtures/valid/referenced-scaling.valid.json +67 -0
  68. package/spec/fixtures/valid/storage-leftovers-simple.valid.json +27 -0
  69. package/spec/fixtures/valid/storage-leftovers-structured.valid.json +43 -0
  70. package/spec/fixtures/valid/structured-nested-step-sections.valid.json +84 -0
  71. package/spec/schemas/stacks-registry.schema.json +108 -0
  72. package/spec/soustack.schema.json +2379 -0
  73. package/spec/stacks/compute.schema.json +7 -0
  74. package/spec/stacks/compute@1.md +22 -0
  75. package/spec/stacks/dietary.schema.json +45 -0
  76. package/spec/stacks/dietary@1.md +24 -0
  77. package/spec/stacks/equipment.schema.json +98 -0
  78. package/spec/stacks/equipment@1.md +244 -0
  79. package/spec/stacks/illustrated.schema.json +54 -0
  80. package/spec/stacks/illustrated@1.md +24 -0
  81. package/spec/stacks/prep.schema.json +76 -0
  82. package/spec/stacks/prep@1.md +276 -0
  83. package/spec/stacks/quantified.schema.json +74 -0
  84. package/spec/stacks/quantified@1.md +24 -0
  85. package/spec/stacks/referenced.schema.json +96 -0
  86. package/spec/stacks/referenced@1.md +23 -0
  87. package/spec/stacks/registry.json +112 -0
  88. package/spec/stacks/scaling.schema.json +99 -0
  89. package/spec/stacks/scaling@1.md +238 -0
  90. package/spec/stacks/storage.schema.json +132 -0
  91. package/spec/stacks/storage@1.md +256 -0
  92. package/spec/stacks/structured.schema.json +48 -0
  93. package/spec/stacks/structured@1.md +24 -0
  94. package/spec/stacks/substitutions.schema.json +43 -0
  95. package/spec/stacks/substitutions@1.md +24 -0
  96. package/spec/stacks/techniques.schema.json +28 -0
  97. package/spec/stacks/techniques@1.md +23 -0
  98. package/spec/stacks/timed.schema.json +60 -0
  99. package/spec/stacks/timed@1.md +23 -0
  100. package/src/defs/common.schema.json +46 -0
  101. package/src/defs/duration.schema.json +33 -0
  102. package/src/defs/entities.schema.json +111 -0
  103. package/src/defs/ingredientQuantified.schema.json +9 -0
  104. package/src/defs/quantity.schema.json +16 -0
  105. package/src/defs/scalingRule.schema.json +127 -0
  106. package/src/defs/temperature.schema.json +63 -0
  107. package/src/profiles/base.schema.json +2 -2
  108. package/src/profiles/equipped.schema.json +10 -0
  109. package/src/profiles/illustrated.schema.json +4 -4
  110. package/src/profiles/lite.schema.json +10 -0
  111. package/src/profiles/prepped.schema.json +10 -0
  112. package/src/profiles/scalable.schema.json +6 -6
  113. package/src/profiles/timed.schema.json +10 -0
  114. package/src/schema.json +2271 -248
  115. package/src/schemas/stacks-registry.schema.json +108 -0
  116. package/src/soustack.schema.json +2271 -248
  117. package/src/stacks/compute.schema.json +7 -0
  118. package/src/stacks/compute@1.md +22 -0
  119. package/src/stacks/dietary.schema.json +45 -0
  120. package/src/stacks/dietary@1.md +24 -0
  121. package/src/stacks/equipment.schema.json +98 -0
  122. package/src/stacks/equipment@1.md +244 -0
  123. package/src/stacks/illustrated.schema.json +54 -0
  124. package/src/stacks/illustrated@1.md +24 -0
  125. package/src/stacks/prep.schema.json +76 -0
  126. package/src/stacks/prep@1.md +276 -0
  127. package/src/stacks/quantified.schema.json +74 -0
  128. package/src/stacks/quantified@1.md +24 -0
  129. package/src/stacks/referenced.schema.json +96 -0
  130. package/src/stacks/referenced@1.md +23 -0
  131. package/src/stacks/registry.json +112 -0
  132. package/src/stacks/scaling.schema.json +99 -0
  133. package/src/stacks/scaling@1.md +238 -0
  134. package/src/stacks/storage.schema.json +132 -0
  135. package/src/stacks/storage@1.md +256 -0
  136. package/src/stacks/structured.schema.json +48 -0
  137. package/src/stacks/structured@1.md +24 -0
  138. package/src/stacks/substitutions.schema.json +43 -0
  139. package/src/stacks/substitutions@1.md +24 -0
  140. package/src/stacks/techniques.schema.json +28 -0
  141. package/src/stacks/techniques@1.md +23 -0
  142. package/src/stacks/timed.schema.json +60 -0
  143. package/src/stacks/timed@1.md +23 -0
  144. package/src/profiles/cookable.schema.json +0 -18
  145. package/src/profiles/quantified.schema.json +0 -43
  146. package/src/profiles/schedulable.schema.json +0 -43
@@ -0,0 +1,256 @@
1
+ #storage@1
2
+
3
+ ---
4
+
5
+ ## Purpose
6
+
7
+ The `storage@1` stack enables recipes to declare storage conditions and duration for prepared dishes, with optional leftovers and reheating guidance.
8
+
9
+ This stack is adoption-first: storage can be declared with minimal information, or extended with detailed leftovers and reheating instructions.
10
+
11
+ ---
12
+
13
+ ## Requirements
14
+
15
+ A document that declares `storage@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 `storage@1` is declared, the document MUST include a top-level `storage` object.
25
+
26
+ ### Storage Object
27
+
28
+ The `storage` object MUST include exactly one of:
29
+ • `roomTemp`: storage at room temperature
30
+ • `refrigerated`: storage in refrigeration
31
+ • `frozen`: storage in freezing conditions
32
+
33
+ Each storage method is a `storageMethod` object with:
34
+ • `duration` (required): ISO 8601 duration string (pattern `^P`)
35
+ • `notes` (optional): string
36
+ • `metadata` (optional): object
37
+
38
+ ### Leftovers and Reheating
39
+
40
+ The `storage` object MAY include an optional `leftovers` field for leftovers and reheating guidance.
41
+
42
+ ---
43
+
44
+ ## Leftovers and Reheating
45
+
46
+ The `leftovers` object supports:
47
+
48
+ • `notes` (optional): string with general guidance
49
+ • `reheat` (optional): array of reheating instructions (see below)
50
+ • `portioning` (optional): portion guidance object
51
+
52
+ ### Reheat Field
53
+
54
+ The `reheat` field supports two formats:
55
+
56
+ #### Simple (Array of Strings)
57
+
58
+ An array of freeform string instructions:
59
+
60
+ ```json
61
+ {
62
+ "storage": {
63
+ "refrigerated": {
64
+ "duration": { "iso8601": "P4D" }
65
+ },
66
+ "leftovers": {
67
+ "notes": "Store in an airtight container.",
68
+ "reheat": [
69
+ "Microwave 2–3 minutes, stirring halfway.",
70
+ "Or warm in a skillet over medium heat with a splash of water."
71
+ ]
72
+ }
73
+ }
74
+ }
75
+ ```
76
+
77
+ #### Structured (Array of Objects)
78
+
79
+ An array of structured reheating instruction objects:
80
+
81
+ ```json
82
+ {
83
+ "storage": {
84
+ "frozen": {
85
+ "duration": { "iso8601": "P2M" }
86
+ },
87
+ "leftovers": {
88
+ "portioning": { "notes": "Cool completely, then portion into containers." },
89
+ "reheat": [
90
+ {
91
+ "method": "microwave",
92
+ "duration": { "minMinutes": 2, "maxMinutes": 3 },
93
+ "notes": "Stir halfway."
94
+ },
95
+ {
96
+ "method": "oven",
97
+ "temp": { "value": 350, "unit": "F" },
98
+ "notes": "Cover and heat until hot throughout."
99
+ }
100
+ ]
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ ### Reheat Instruction Object
107
+
108
+ Each structured reheating instruction includes:
109
+
110
+ • `method` (required): string describing the reheating method (freeform in v1)
111
+ • `temp` (optional): object with `value` (number) and `unit` ("F" or "C")
112
+ • `duration` (optional): object with `minMinutes` and/or `maxMinutes` (integers >= 0)
113
+ • `notes` (optional): string
114
+
115
+ ### Reheat Duration
116
+
117
+ The `duration` object supports:
118
+ • `minMinutes` (optional): integer >= 0
119
+ • `maxMinutes` (optional): integer >= 0
120
+ • At least one of `minMinutes` or `maxMinutes` must be present
121
+
122
+ If both are present, `minMinutes` should be <= `maxMinutes` (semantic validation may enforce this in tooling).
123
+
124
+ ### Portioning
125
+
126
+ The `portioning` object includes:
127
+ • `notes` (required): string with portioning guidance
128
+ • `recommendedPortion` (optional): object with `quantity` (number) and `unit` (string)
129
+
130
+ ---
131
+
132
+ ## Semantics
133
+
134
+ ### Storage Methods
135
+
136
+ Storage methods (`roomTemp`, `refrigerated`, `frozen`) are mutually exclusive. Exactly one must be present.
137
+
138
+ ### Reheat Method
139
+
140
+ The `method` field in structured reheating instructions is freeform in v1. Consumers may map common values (e.g., "microwave", "oven", "stovetop") to display or planning features, but validation does not enforce specific values.
141
+
142
+ ### Scaling
143
+
144
+ If no scaling factor exists in the document, leftovers guidance does not change. Leftovers guidance is not scaled by recipe scale factors.
145
+
146
+ ---
147
+
148
+ ## Composition
149
+
150
+ The storage stack is composable with other stacks:
151
+
152
+ • No hard dependency on other stacks
153
+ • Remains monotonic: does not close objects needed by other stacks
154
+ • `leftovers` is optional even when the stack is present
155
+
156
+ ---
157
+
158
+ ## Semantic Validation Rules (Normative)
159
+
160
+ Validators MUST enforce the following rules:
161
+
162
+ 1. Storage method requirement
163
+ The `storage` object MUST include exactly one of `roomTemp`, `refrigerated`, or `frozen`.
164
+
165
+ 2. Duration requirement
166
+ Each storage method object MUST include a `duration` field.
167
+
168
+ 3. Reheat instruction method requirement
169
+ If `leftovers.reheat` includes structured instruction objects, each object MUST include a `method` field.
170
+
171
+ 4. Reheat duration validation
172
+ If a `reheatInstruction.duration` includes both `minMinutes` and `maxMinutes`, `minMinutes` SHOULD be <= `maxMinutes` (tooling may warn but not fail validation).
173
+
174
+ ---
175
+
176
+ ## Examples
177
+
178
+ Minimal storage
179
+
180
+ ```json
181
+ {
182
+ "storage": {
183
+ "refrigerated": {
184
+ "duration": { "iso8601": "P3D" }
185
+ }
186
+ }
187
+ }
188
+ ```
189
+
190
+ Storage with simple leftovers
191
+
192
+ ```json
193
+ {
194
+ "storage": {
195
+ "refrigerated": {
196
+ "duration": { "iso8601": "P4D" }
197
+ },
198
+ "leftovers": {
199
+ "notes": "Store in an airtight container.",
200
+ "reheat": [
201
+ "Microwave 2–3 minutes, stirring halfway.",
202
+ "Or warm in a skillet over medium heat with a splash of water."
203
+ ]
204
+ }
205
+ }
206
+ }
207
+ ```
208
+
209
+ Storage with structured reheating
210
+
211
+ ```json
212
+ {
213
+ "storage": {
214
+ "frozen": {
215
+ "duration": { "iso8601": "P2M" }
216
+ },
217
+ "leftovers": {
218
+ "portioning": { "notes": "Cool completely, then portion into containers." },
219
+ "reheat": [
220
+ {
221
+ "method": "microwave",
222
+ "duration": { "minMinutes": 2, "maxMinutes": 3 },
223
+ "notes": "Stir halfway."
224
+ },
225
+ {
226
+ "method": "oven",
227
+ "temp": { "value": 350, "unit": "F" },
228
+ "notes": "Cover and heat until hot throughout."
229
+ }
230
+ ]
231
+ }
232
+ }
233
+ }
234
+ ```
235
+
236
+ Storage with portioning
237
+
238
+ ```json
239
+ {
240
+ "storage": {
241
+ "refrigerated": {
242
+ "duration": { "iso8601": "P5D" }
243
+ },
244
+ "leftovers": {
245
+ "portioning": {
246
+ "notes": "Portion into individual servings before storing.",
247
+ "recommendedPortion": {
248
+ "quantity": 1,
249
+ "unit": "cup"
250
+ }
251
+ }
252
+ }
253
+ }
254
+ }
255
+ ```
256
+
@@ -0,0 +1,48 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://soustack.spec/stacks/structured.schema.json",
4
+ "title": "Structured Stack",
5
+ "type": "object",
6
+ "properties": {
7
+ "instructions": {
8
+ "type": "array",
9
+ "items": {
10
+ "anyOf": [
11
+ { "$ref": "#/$defs/step" },
12
+ { "$ref": "#/$defs/stepSection" }
13
+ ]
14
+ }
15
+ }
16
+ },
17
+ "required": ["instructions"],
18
+ "$defs": {
19
+ "step": {
20
+ "allOf": [
21
+ { "$ref": "../defs/entities.schema.json#/$defs/StepBase" },
22
+ { "required": ["id"] }
23
+ ]
24
+ },
25
+ "stepSection": {
26
+ "type": "object",
27
+ "properties": {
28
+ "section": { "type": "string" },
29
+ "steps": {
30
+ "type": "array",
31
+ "items": {
32
+ "anyOf": [
33
+ { "$ref": "#/$defs/step" },
34
+ { "$ref": "#/$defs/stepSection" }
35
+ ]
36
+ }
37
+ },
38
+ "metadata": { "type": "object", "additionalProperties": true }
39
+ },
40
+ "required": ["section", "steps"],
41
+ "additionalProperties": false,
42
+ "patternProperties": {
43
+ "^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
44
+ }
45
+ }
46
+ },
47
+ "additionalProperties": false
48
+ }
@@ -0,0 +1,24 @@
1
+ # structured@1
2
+
3
+ ## Purpose
4
+ The `structured@1` stack requires that instruction steps are structured objects with stable IDs, enabling cross-referencing, timing, and programmatic manipulation.
5
+
6
+ ## Adds
7
+ - Top-level `instructions` array with structured step objects containing `id` and `text` fields.
8
+ - Steps may include `dependsOn`, `inputs`, `techniqueIds`, `usesEquipment`, `temperature`, `timing`, `images`, `videos`, and `metadata`.
9
+ - Support for nested step sections.
10
+
11
+ ## Requires
12
+ - None
13
+
14
+ ## Semantics
15
+ - MUST: Each step object must include `id` and `text` fields.
16
+ - MUST: Step IDs must be unique within the instructions array.
17
+ - NOTE: This stack is a prerequisite for `timed@1` and `referenced@1`.
18
+
19
+ ## Composition Notes
20
+ - This stack is monotonic: it adds requirements or fields without removing expressiveness.
21
+ - Interaction: Required by `timed@1` and `referenced@1`. Enables equipment references when combined with `equipment@1`.
22
+
23
+
24
+
@@ -0,0 +1,43 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://soustack.spec/stacks/substitutions.schema.json",
4
+ "title": "Substitutions Stack",
5
+ "type": "object",
6
+ "properties": {
7
+ "substitutions": {
8
+ "type": "array",
9
+ "items": {
10
+ "type": "object",
11
+ "properties": {
12
+ "for": { "type": "string" },
13
+ "alternatives": {
14
+ "type": "array",
15
+ "items": {
16
+ "type": "object",
17
+ "properties": {
18
+ "name": { "type": "string" },
19
+ "ratio": { "type": "string" },
20
+ "metadata": { "type": "object", "additionalProperties": true }
21
+ },
22
+ "required": ["name", "ratio"],
23
+ "additionalProperties": false,
24
+ "patternProperties": {
25
+ "^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
26
+ }
27
+ },
28
+ "minItems": 1
29
+ },
30
+ "metadata": { "type": "object", "additionalProperties": true }
31
+ },
32
+ "required": ["for", "alternatives"],
33
+ "additionalProperties": false,
34
+ "patternProperties": {
35
+ "^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
36
+ }
37
+ },
38
+ "minItems": 1
39
+ }
40
+ },
41
+ "required": ["substitutions"],
42
+ "additionalProperties": false
43
+ }
@@ -0,0 +1,24 @@
1
+ # substitutions@1
2
+
3
+ ## Purpose
4
+ The `substitutions@1` stack enables recipes to declare ingredient substitutions with alternatives and ratios.
5
+
6
+ ## Adds
7
+ - Top-level `substitutions` array with substitution objects.
8
+ - Each substitution includes `for` (ingredient ID) and `alternatives` array.
9
+ - Each alternative includes `name` and `ratio` fields.
10
+
11
+ ## Requires
12
+ - `referenced@1`
13
+
14
+ ## Semantics
15
+ - MUST: The `for` field must reference an ingredient ID that exists in the ingredients array.
16
+ - MUST: Each substitution must include at least one alternative.
17
+ - NOTE: This stack requires `referenced@1` to ensure ingredient IDs are available for reference.
18
+
19
+ ## Composition Notes
20
+ - This stack is monotonic: it adds requirements or fields without removing expressiveness.
21
+ - Interaction: Requires `referenced@1` for ingredient ID resolution. Substitutions are informational and do not affect recipe structure.
22
+
23
+
24
+
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://soustack.spec/stacks/techniques.schema.json",
4
+ "title": "Techniques Stack",
5
+ "type": "object",
6
+ "properties": {
7
+ "techniques": {
8
+ "type": "array",
9
+ "items": {
10
+ "type": "object",
11
+ "properties": {
12
+ "id": { "type": "string" },
13
+ "name": { "type": "string" },
14
+ "description": { "type": "string" },
15
+ "metadata": { "type": "object", "additionalProperties": true }
16
+ },
17
+ "required": ["id", "name"],
18
+ "additionalProperties": false,
19
+ "patternProperties": {
20
+ "^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
21
+ }
22
+ },
23
+ "minItems": 1
24
+ }
25
+ },
26
+ "required": ["techniques"],
27
+ "additionalProperties": false
28
+ }
@@ -0,0 +1,23 @@
1
+ # techniques@1
2
+
3
+ ## Purpose
4
+ The `techniques@1` stack enables recipes to declare cooking techniques used in the recipe, with optional descriptions.
5
+
6
+ ## Adds
7
+ - Top-level `techniques` array with technique objects.
8
+ - Each technique includes `id` and `name` fields, with optional `description` and `metadata`.
9
+
10
+ ## Requires
11
+ - None
12
+
13
+ ## Semantics
14
+ - MUST: The `techniques` array must contain at least one technique.
15
+ - MUST: Each technique must include `id` and `name` fields.
16
+ - NOTE: Technique IDs may be referenced in step `techniqueIds` arrays when `structured@1` is present.
17
+
18
+ ## Composition Notes
19
+ - This stack is monotonic: it adds requirements or fields without removing expressiveness.
20
+ - Interaction: Works with `structured@1` to enable step-level technique references. No hard dependencies on other stacks.
21
+
22
+
23
+
@@ -0,0 +1,60 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://soustack.spec/stacks/timed.schema.json",
4
+ "title": "Timed Stack",
5
+ "type": "object",
6
+ "properties": {
7
+ "instructions": {
8
+ "type": "array",
9
+ "items": {
10
+ "anyOf": [
11
+ { "$ref": "#/$defs/timedStep" },
12
+ { "$ref": "#/$defs/timedStepSection" }
13
+ ]
14
+ }
15
+ }
16
+ },
17
+ "required": ["instructions"],
18
+ "allOf": [
19
+ { "$ref": "./structured.schema.json" }
20
+ ],
21
+ "$defs": {
22
+ "timedStep": {
23
+ "allOf": [
24
+ { "$ref": "../defs/entities.schema.json#/$defs/StepBase" },
25
+ {
26
+ "properties": {
27
+ "timing": {
28
+ "allOf": [
29
+ { "$ref": "../defs/entities.schema.json#/$defs/StepBase/properties/timing" },
30
+ { "required": ["activity"], "anyOf": [ { "required": ["duration"] }, { "required": ["completionCue"] } ] }
31
+ ]
32
+ }
33
+ },
34
+ "required": ["id", "timing"]
35
+ }
36
+ ]
37
+ },
38
+ "timedStepSection": {
39
+ "type": "object",
40
+ "properties": {
41
+ "section": { "type": "string" },
42
+ "steps": {
43
+ "type": "array",
44
+ "items": {
45
+ "anyOf": [
46
+ { "$ref": "#/$defs/timedStep" },
47
+ { "$ref": "#/$defs/timedStepSection" }
48
+ ]
49
+ }
50
+ },
51
+ "metadata": { "type": "object", "additionalProperties": true }
52
+ },
53
+ "required": ["section", "steps"],
54
+ "additionalProperties": false,
55
+ "patternProperties": {
56
+ "^x-": { "$ref": "../defs/common.schema.json#/properties/extensionLaneValue" }
57
+ }
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,23 @@
1
+ # timed@1
2
+
3
+ ## Purpose
4
+ The `timed@1` stack enables recipes to include timing information for steps, supporting scheduling and time-based planning.
5
+
6
+ ## Adds
7
+ - Step objects must include a `timing` field with `activity` (active/passive) and either `duration` or `completionCue`.
8
+ - Timing may include duration ranges (minMinutes/maxMinutes) or completion cues.
9
+
10
+ ## Requires
11
+ - `structured@1`
12
+
13
+ ## Semantics
14
+ - MUST: Each step must include a `timing` object with `activity` field.
15
+ - MUST: Each timing object must include either `duration` or `completionCue`.
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 `compute@1` for deterministic scheduling. Works with `quantified@1` for computational recipe planning.
21
+
22
+
23
+
@@ -1,18 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "http://soustack.org/schema/v0.3.0/profiles/cookable",
4
- "title": "Soustack Cookable Profile Schema",
5
- "description": "Extends the base schema to require structured yield + time metadata and non-empty ingredient/instruction lists.",
6
- "allOf": [
7
- { "$ref": "http://soustack.org/schema/v0.3.0" },
8
- {
9
- "required": ["yield", "time", "ingredients", "instructions"],
10
- "properties": {
11
- "yield": { "$ref": "http://soustack.org/schema/v0.3.0#/definitions/yield" },
12
- "time": { "$ref": "http://soustack.org/schema/v0.3.0#/definitions/time" },
13
- "ingredients": { "type": "array", "minItems": 1 },
14
- "instructions": { "type": "array", "minItems": 1 }
15
- }
16
- }
17
- ]
18
- }
@@ -1,43 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "http://soustack.org/schema/v0.3.0/profiles/quantified",
4
- "title": "Soustack Quantified Profile Schema",
5
- "description": "Extends the base schema to require quantified ingredient entries.",
6
- "allOf": [
7
- { "$ref": "http://soustack.org/schema/v0.3.0" },
8
- {
9
- "properties": {
10
- "ingredients": {
11
- "type": "array",
12
- "items": {
13
- "anyOf": [
14
- { "$ref": "#/definitions/quantifiedIngredient" },
15
- { "$ref": "#/definitions/quantifiedIngredientSubsection" }
16
- ]
17
- }
18
- }
19
- }
20
- }
21
- ],
22
- "definitions": {
23
- "quantifiedIngredient": {
24
- "allOf": [
25
- { "$ref": "http://soustack.org/schema/v0.3.0#/definitions/ingredient" },
26
- { "required": ["item", "quantity"] }
27
- ]
28
- },
29
- "quantifiedIngredientSubsection": {
30
- "allOf": [
31
- { "$ref": "http://soustack.org/schema/v0.3.0#/definitions/ingredientSubsection" },
32
- {
33
- "properties": {
34
- "items": {
35
- "type": "array",
36
- "items": { "$ref": "#/definitions/quantifiedIngredient" }
37
- }
38
- }
39
- }
40
- ]
41
- }
42
- }
43
- }
@@ -1,43 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "$id": "http://soustack.org/schema/v0.3.0/profiles/schedulable",
4
- "title": "Soustack Schedulable Profile Schema",
5
- "description": "Extends the base schema to ensure every instruction is fully scheduled.",
6
- "allOf": [
7
- { "$ref": "http://soustack.org/schema/v0.3.0" },
8
- {
9
- "properties": {
10
- "instructions": {
11
- "type": "array",
12
- "items": {
13
- "anyOf": [
14
- { "$ref": "#/definitions/schedulableInstruction" },
15
- { "$ref": "#/definitions/schedulableInstructionSubsection" }
16
- ]
17
- }
18
- }
19
- }
20
- }
21
- ],
22
- "definitions": {
23
- "schedulableInstruction": {
24
- "allOf": [
25
- { "$ref": "http://soustack.org/schema/v0.3.0#/definitions/instruction" },
26
- { "required": ["id", "timing"] }
27
- ]
28
- },
29
- "schedulableInstructionSubsection": {
30
- "allOf": [
31
- { "$ref": "http://soustack.org/schema/v0.3.0#/definitions/instructionSubsection" },
32
- {
33
- "properties": {
34
- "items": {
35
- "type": "array",
36
- "items": { "$ref": "#/definitions/schedulableInstruction" }
37
- }
38
- }
39
- }
40
- ]
41
- }
42
- }
43
- }