kalup 0.1.0

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 (145) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +4 -0
  3. package/README.md +68 -0
  4. package/bin/kalup.mjs +13 -0
  5. package/dist/commands-C--Xsk1p.mjs +16145 -0
  6. package/dist/commands.d.mts +191 -0
  7. package/dist/commands.mjs +2 -0
  8. package/dist/context-D10Syqfd.d.mts +1265 -0
  9. package/dist/host-BJWvo3sX.mjs +390 -0
  10. package/dist/host.d.mts +44 -0
  11. package/dist/host.mjs +2 -0
  12. package/dist/index.d.mts +1 -0
  13. package/dist/index.mjs +14 -0
  14. package/dist/schemas/blueprint-1.schema.json +151 -0
  15. package/dist/schemas/blueprints-lock-1.schema.json +76 -0
  16. package/dist/schemas/ir-1.schema.json +379 -0
  17. package/dist/schemas/plan-1.schema.json +868 -0
  18. package/dist/schemas/state-1.schema.json +98 -0
  19. package/docs/apply.md +64 -0
  20. package/docs/blueprints.md +86 -0
  21. package/docs/compare.md +73 -0
  22. package/docs/config.md +88 -0
  23. package/docs/dictionary.md +43 -0
  24. package/docs/errors/E_ACCEPT_UNMATCHED.md +17 -0
  25. package/docs/errors/E_APPROVAL_REQUIRED.md +17 -0
  26. package/docs/errors/E_APPROVE_CREDENTIAL.md +17 -0
  27. package/docs/errors/E_APPROVE_MISMATCH.md +17 -0
  28. package/docs/errors/E_AUTH.md +17 -0
  29. package/docs/errors/E_BAD_CHAIN.md +21 -0
  30. package/docs/errors/E_BINDING_CHANGED.md +17 -0
  31. package/docs/errors/E_BIOME_CONFIG.md +17 -0
  32. package/docs/errors/E_BLUEPRINT_ADDED.md +17 -0
  33. package/docs/errors/E_BLUEPRINT_COLLISION.md +17 -0
  34. package/docs/errors/E_BLUEPRINT_INTEGRITY.md +17 -0
  35. package/docs/errors/E_BLUEPRINT_LOCK.md +17 -0
  36. package/docs/errors/E_BLUEPRINT_ORIGINAL.md +17 -0
  37. package/docs/errors/E_BLUEPRINT_REF.md +17 -0
  38. package/docs/errors/E_BLUEPRINT_REQUIRES.md +17 -0
  39. package/docs/errors/E_BLUEPRINT_SCHEMA.md +17 -0
  40. package/docs/errors/E_BLUEPRINT_SOURCE.md +17 -0
  41. package/docs/errors/E_BLUEPRINT_UNKNOWN.md +17 -0
  42. package/docs/errors/E_BUDGET.md +17 -0
  43. package/docs/errors/E_CANCELLED.md +21 -0
  44. package/docs/errors/E_CONFIG_EXISTS.md +17 -0
  45. package/docs/errors/E_DAILY_LIMIT.md +17 -0
  46. package/docs/errors/E_DEFAULT_TARGET.md +17 -0
  47. package/docs/errors/E_DUPLICATE_ADDRESS.md +17 -0
  48. package/docs/errors/E_DUPLICATE_ALIAS.md +24 -0
  49. package/docs/errors/E_DUPLICATE_KEY.md +24 -0
  50. package/docs/errors/E_DUPLICATE_OPTION.md +25 -0
  51. package/docs/errors/E_DUPLICATE_PORTAL.md +24 -0
  52. package/docs/errors/E_FIRST_PULL.md +18 -0
  53. package/docs/errors/E_HS_PREFIX.md +21 -0
  54. package/docs/errors/E_HTTP.md +17 -0
  55. package/docs/errors/E_INCOMPLETE.md +23 -0
  56. package/docs/errors/E_IR_SCHEMA.md +18 -0
  57. package/docs/errors/E_JOURNAL_WRITE.md +17 -0
  58. package/docs/errors/E_KEY_COLLISION.md +22 -0
  59. package/docs/errors/E_KEY_INVALID.md +19 -0
  60. package/docs/errors/E_LIFECYCLE.md +23 -0
  61. package/docs/errors/E_LOCKED.md +17 -0
  62. package/docs/errors/E_LOCK_DIR.md +17 -0
  63. package/docs/errors/E_MISSING_EXPORT.md +17 -0
  64. package/docs/errors/E_MISSING_KEY.md +17 -0
  65. package/docs/errors/E_NOT_DATA.md +21 -0
  66. package/docs/errors/E_NO_CONFIG.md +17 -0
  67. package/docs/errors/E_NO_TARGETS.md +17 -0
  68. package/docs/errors/E_OVERRIDE_AMBIGUOUS.md +21 -0
  69. package/docs/errors/E_OVERRIDE_DEFINITION.md +26 -0
  70. package/docs/errors/E_OVERRIDE_NAME.md +23 -0
  71. package/docs/errors/E_PLAN_DELETE.md +17 -0
  72. package/docs/errors/E_PLAN_DESTINATION.md +17 -0
  73. package/docs/errors/E_PLAN_DIGEST.md +17 -0
  74. package/docs/errors/E_PLAN_INVALID.md +17 -0
  75. package/docs/errors/E_PLAN_RISK.md +17 -0
  76. package/docs/errors/E_PLAN_SCHEMA.md +17 -0
  77. package/docs/errors/E_PLAN_STALE.md +17 -0
  78. package/docs/errors/E_PLAN_VERSION.md +18 -0
  79. package/docs/errors/E_POLICY_CHANGED.md +17 -0
  80. package/docs/errors/E_PORTAL_ID.md +17 -0
  81. package/docs/errors/E_PREVENT_DESTROY.md +17 -0
  82. package/docs/errors/E_PROJECT_WRITE.md +17 -0
  83. package/docs/errors/E_PROTECTED_SAVED_PLAN.md +17 -0
  84. package/docs/errors/E_PULL_INVALID.md +20 -0
  85. package/docs/errors/E_RATE_LIMIT.md +17 -0
  86. package/docs/errors/E_REBIND_STANDARD.md +17 -0
  87. package/docs/errors/E_REFERENCE_DEFINITION.md +21 -0
  88. package/docs/errors/E_RM_DEPENDENTS.md +17 -0
  89. package/docs/errors/E_SCOPE.md +17 -0
  90. package/docs/errors/E_SETTING_LEVEL.md +21 -0
  91. package/docs/errors/E_SETTING_VALUE.md +23 -0
  92. package/docs/errors/E_SNAPSHOT.md +17 -0
  93. package/docs/errors/E_STANDARD_OBJECT.md +21 -0
  94. package/docs/errors/E_STATE_CHANGED.md +19 -0
  95. package/docs/errors/E_STATE_CONFLICT.md +17 -0
  96. package/docs/errors/E_STATE_INVALID.md +17 -0
  97. package/docs/errors/E_STATE_SCHEMA.md +17 -0
  98. package/docs/errors/E_STATE_WRITE.md +19 -0
  99. package/docs/errors/E_STRICT_WITHOUT_OPTIONS.md +21 -0
  100. package/docs/errors/E_TAKE_UNMATCHED.md +19 -0
  101. package/docs/errors/E_TARGET_NAME.md +17 -0
  102. package/docs/errors/E_TARGET_PORTAL_MISMATCH.md +19 -0
  103. package/docs/errors/E_TARGET_REQUIRED.md +17 -0
  104. package/docs/errors/E_TOMBSTONE_ADDRESS.md +23 -0
  105. package/docs/errors/E_TOMBSTONE_CONFLICT.md +17 -0
  106. package/docs/errors/E_TYPE_FIELDTYPE.md +21 -0
  107. package/docs/errors/E_UNCERTAIN_WRITE.md +17 -0
  108. package/docs/errors/E_UNEXPECTED.md +17 -0
  109. package/docs/errors/E_UNKNOWN_BUILDER.md +21 -0
  110. package/docs/errors/E_UNKNOWN_GROUP.md +21 -0
  111. package/docs/errors/E_UNKNOWN_INCLUDE.md +17 -0
  112. package/docs/errors/E_UNKNOWN_OBJECT.md +17 -0
  113. package/docs/errors/E_UNKNOWN_OVERRIDE.md +17 -0
  114. package/docs/errors/E_UNKNOWN_TARGET.md +17 -0
  115. package/docs/errors/E_UNREACHABLE.md +17 -0
  116. package/docs/errors/E_UNSUPPORTED_FILE.md +17 -0
  117. package/docs/errors/E_USAGE.md +17 -0
  118. package/docs/errors/E_WRITE_IN_READ_MODE.md +17 -0
  119. package/docs/errors/E_WRITE_NOT_ALLOWED.md +17 -0
  120. package/docs/errors/W_BLUEPRINT_DOWNGRADE.md +17 -0
  121. package/docs/errors/W_CODEC_MISMATCH.md +18 -0
  122. package/docs/errors/W_INCOMPLETE.md +19 -0
  123. package/docs/errors/W_JSON_FIELDTYPE.md +17 -0
  124. package/docs/errors/W_KEY_COLLISION.md +17 -0
  125. package/docs/errors/W_LARGE_SCOPE.md +23 -0
  126. package/docs/errors/W_LIMIT_HEADROOM.md +19 -0
  127. package/docs/errors/W_LIMIT_UNREADABLE.md +17 -0
  128. package/docs/errors/W_MODE_SHADOWED.md +17 -0
  129. package/docs/errors/W_OVERRIDE_OPTION.md +17 -0
  130. package/docs/errors/W_PIN_EXPIRES.md +17 -0
  131. package/docs/errors/W_PREFIX.md +17 -0
  132. package/docs/errors/W_RATE_HEADERS.md +21 -0
  133. package/docs/errors/W_RATE_LIMIT.md +17 -0
  134. package/docs/errors/W_UNADDRESSABLE_NAME.md +21 -0
  135. package/docs/errors/W_UNFINISHED_APPLY.md +19 -0
  136. package/docs/errors/W_UNRESOLVED.md +17 -0
  137. package/docs/errors/W_UNSUPPORTED_TYPE.md +19 -0
  138. package/docs/errors/W_UNVERIFIED.md +17 -0
  139. package/docs/plan.md +85 -0
  140. package/docs/pull.md +83 -0
  141. package/docs/rm.md +44 -0
  142. package/docs/snapshot.md +52 -0
  143. package/docs/state.md +37 -0
  144. package/docs/targets.md +58 -0
  145. package/package.json +86 -0
@@ -0,0 +1,868 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://kalup.dev/schemas/plan-1.schema.json",
4
+ "title": "Kalup plan, version 1",
5
+ "description": "What `kalup plan` would do to one target, with the context an approval binds to. Closed at every level, so a saved plan carries nothing this schema does not name, and a new field is a new format version.",
6
+ "type": "object",
7
+ "required": [
8
+ "format",
9
+ "planId",
10
+ "generator",
11
+ "target",
12
+ "stateLineage",
13
+ "stateSerial",
14
+ "normVersions",
15
+ "bindings",
16
+ "irHash",
17
+ "counts",
18
+ "permanentNames",
19
+ "budget",
20
+ "writesHash",
21
+ "preflight",
22
+ "coverage",
23
+ "notCovered",
24
+ "orphans",
25
+ "missing",
26
+ "steps"
27
+ ],
28
+ "properties": {
29
+ "format": {
30
+ "const": "plan/1"
31
+ },
32
+ "planId": {
33
+ "description": "pl_ plus the first 12 hex characters of writesHash.",
34
+ "type": "string",
35
+ "pattern": "^pl_[0-9a-f]{12}$"
36
+ },
37
+ "generator": {
38
+ "type": "object",
39
+ "required": ["name", "version"],
40
+ "properties": {
41
+ "name": {
42
+ "type": "string"
43
+ },
44
+ "version": {
45
+ "type": "string"
46
+ }
47
+ },
48
+ "additionalProperties": false
49
+ },
50
+ "target": {
51
+ "description": "The verified destination and its effective policy. protected defaults to true when accountType is STANDARD, drift and adopt to hold, allowDestroy to false, yesLimit to 25 and takeover to no object.",
52
+ "type": "object",
53
+ "required": [
54
+ "name",
55
+ "portalId",
56
+ "accountType",
57
+ "uiDomain",
58
+ "protected",
59
+ "drift",
60
+ "adopt",
61
+ "allowDestroy",
62
+ "yesLimit",
63
+ "takeover"
64
+ ],
65
+ "properties": {
66
+ "name": {
67
+ "type": "string"
68
+ },
69
+ "portalId": {
70
+ "type": "integer",
71
+ "minimum": 1
72
+ },
73
+ "accountType": {
74
+ "type": "string"
75
+ },
76
+ "uiDomain": {
77
+ "type": "string"
78
+ },
79
+ "protected": {
80
+ "type": "boolean"
81
+ },
82
+ "drift": {
83
+ "enum": ["hold", "overwrite"]
84
+ },
85
+ "adopt": {
86
+ "enum": ["hold", "overwrite"]
87
+ },
88
+ "allowDestroy": {
89
+ "type": "boolean"
90
+ },
91
+ "yesLimit": {
92
+ "type": "integer",
93
+ "minimum": 0,
94
+ "maximum": 1000
95
+ },
96
+ "takeover": {
97
+ "description": "The objects whose mode on this target is takeover, sorted.",
98
+ "type": "array",
99
+ "uniqueItems": true,
100
+ "items": { "type": "string" }
101
+ }
102
+ },
103
+ "additionalProperties": false
104
+ },
105
+ "stateLineage": {
106
+ "description": "The lineage of the state the plan was made against. null without state, never a made-up lineage.",
107
+ "type": ["string", "null"]
108
+ },
109
+ "stateSerial": {
110
+ "description": "The serial of the state the plan was made against. null without state.",
111
+ "type": ["integer", "null"],
112
+ "minimum": 0
113
+ },
114
+ "normVersions": {
115
+ "description": "The normalizer version of each resource type the plan compared with, keyed by type: property, group and object always, and any other type a later version adds. A base written under another version counts as absent.",
116
+ "type": "object",
117
+ "required": ["property", "group", "object"],
118
+ "patternProperties": {
119
+ "^[a-z]+$": {
120
+ "type": "integer",
121
+ "minimum": 1
122
+ }
123
+ },
124
+ "additionalProperties": false
125
+ },
126
+ "bindings": {
127
+ "description": "Every address a non-blocked step depends on whose portal identity is not its logical key.",
128
+ "type": "object",
129
+ "patternProperties": {
130
+ "^[a-z]+:\\S+$": {
131
+ "$ref": "#/$defs/binding"
132
+ }
133
+ },
134
+ "additionalProperties": false
135
+ },
136
+ "irHash": {
137
+ "description": "The config IR, for display only.",
138
+ "$ref": "#/$defs/hash"
139
+ },
140
+ "counts": {
141
+ "description": "Steps by risk, plus held units.",
142
+ "type": "object",
143
+ "required": ["safe", "risky", "destructive", "blocked", "manual", "held"],
144
+ "properties": {
145
+ "safe": {
146
+ "$ref": "#/$defs/count"
147
+ },
148
+ "risky": {
149
+ "$ref": "#/$defs/count"
150
+ },
151
+ "destructive": {
152
+ "$ref": "#/$defs/count"
153
+ },
154
+ "blocked": {
155
+ "$ref": "#/$defs/count"
156
+ },
157
+ "manual": {
158
+ "$ref": "#/$defs/count"
159
+ },
160
+ "held": {
161
+ "$ref": "#/$defs/count"
162
+ }
163
+ },
164
+ "additionalProperties": false
165
+ },
166
+ "permanentNames": {
167
+ "description": "Internal names a first apply to a STANDARD portal would create. They can never be renamed.",
168
+ "$ref": "#/$defs/count"
169
+ },
170
+ "budget": {
171
+ "type": "object",
172
+ "required": ["estimatedCalls", "dailyRemaining"],
173
+ "properties": {
174
+ "estimatedCalls": {
175
+ "$ref": "#/$defs/count"
176
+ },
177
+ "dailyRemaining": {
178
+ "description": "null when the rate headers carry no daily figure.",
179
+ "type": ["integer", "null"]
180
+ }
181
+ },
182
+ "additionalProperties": false
183
+ },
184
+ "writesHash": {
185
+ "description": "sha256 of the approval context: destination, policy, state lineage and serial, normalizer versions, bindings and the steps with an effect.",
186
+ "$ref": "#/$defs/hash"
187
+ },
188
+ "preflight": {
189
+ "type": "object",
190
+ "required": ["limits"],
191
+ "properties": {
192
+ "limits": {
193
+ "type": "array",
194
+ "items": {
195
+ "$ref": "#/$defs/limitReading"
196
+ }
197
+ }
198
+ },
199
+ "additionalProperties": false
200
+ },
201
+ "coverage": {
202
+ "description": "What the observation behind the plan could not see. An incomplete read never authorizes a create.",
203
+ "type": "object",
204
+ "required": ["complete", "unreadable", "unsupported", "excluded"],
205
+ "properties": {
206
+ "complete": {
207
+ "type": "boolean"
208
+ },
209
+ "unreadable": {
210
+ "type": "array",
211
+ "items": {
212
+ "type": "object",
213
+ "required": ["object"],
214
+ "properties": {
215
+ "object": {
216
+ "type": "string"
217
+ },
218
+ "scope": {
219
+ "type": "string"
220
+ }
221
+ },
222
+ "additionalProperties": false
223
+ }
224
+ },
225
+ "unsupported": {
226
+ "type": "array",
227
+ "items": {
228
+ "$ref": "#/$defs/address"
229
+ }
230
+ },
231
+ "excluded": {
232
+ "type": "array",
233
+ "items": {
234
+ "$ref": "#/$defs/address"
235
+ }
236
+ }
237
+ },
238
+ "additionalProperties": false
239
+ },
240
+ "notCovered": {
241
+ "description": "Once per resource type with steps: what HubSpot has no API for.",
242
+ "type": "array",
243
+ "items": {
244
+ "type": "object",
245
+ "required": ["type", "lines"],
246
+ "properties": {
247
+ "type": {
248
+ "type": "string"
249
+ },
250
+ "lines": {
251
+ "type": "array",
252
+ "items": {
253
+ "type": "string"
254
+ }
255
+ }
256
+ },
257
+ "additionalProperties": false
258
+ }
259
+ },
260
+ "orphans": {
261
+ "description": "Resources state owns that config no longer names and no tombstone removes. No step; the note names both rm commands.",
262
+ "type": "array",
263
+ "items": {
264
+ "type": "object",
265
+ "required": ["address", "note"],
266
+ "properties": {
267
+ "address": {
268
+ "$ref": "#/$defs/address"
269
+ },
270
+ "note": {
271
+ "type": "string"
272
+ }
273
+ },
274
+ "additionalProperties": false
275
+ }
276
+ },
277
+ "missing": {
278
+ "description": "Resources state owns that the portal no longer holds. No step; resolve lists the ways out.",
279
+ "type": "array",
280
+ "items": {
281
+ "type": "object",
282
+ "required": ["address", "origin", "archived", "resolve"],
283
+ "properties": {
284
+ "address": {
285
+ "$ref": "#/$defs/address"
286
+ },
287
+ "origin": {
288
+ "enum": ["created", "adopted"]
289
+ },
290
+ "archived": {
291
+ "description": "Whether HubSpot holds it archived; null when that is not known.",
292
+ "type": ["boolean", "null"]
293
+ },
294
+ "archivedAt": {
295
+ "type": "string"
296
+ },
297
+ "resolve": {
298
+ "type": "array",
299
+ "items": {
300
+ "type": "string"
301
+ }
302
+ }
303
+ },
304
+ "additionalProperties": false
305
+ }
306
+ },
307
+ "steps": {
308
+ "type": "array",
309
+ "items": {
310
+ "$ref": "#/$defs/step"
311
+ }
312
+ }
313
+ },
314
+ "additionalProperties": false,
315
+ "$defs": {
316
+ "address": {
317
+ "description": "'<type>:<path>', for example property:companies/billing_status.",
318
+ "type": "string",
319
+ "pattern": "^[a-z]+:\\S+$"
320
+ },
321
+ "hash": {
322
+ "type": "string",
323
+ "pattern": "^sha256:[0-9a-f]{64}$"
324
+ },
325
+ "count": {
326
+ "type": "integer",
327
+ "minimum": 0
328
+ },
329
+ "binding": {
330
+ "description": "name when a name override resolves the address, id for an existing custom object.",
331
+ "type": "object",
332
+ "properties": {
333
+ "name": {
334
+ "type": "string"
335
+ },
336
+ "id": {
337
+ "type": "string"
338
+ }
339
+ },
340
+ "additionalProperties": false
341
+ },
342
+ "limitReading": {
343
+ "description": "One Limits Tracking reading. An unreadable reading blocks nothing.",
344
+ "type": "object",
345
+ "required": ["key", "status"],
346
+ "properties": {
347
+ "key": {
348
+ "type": "string"
349
+ },
350
+ "status": {
351
+ "enum": ["read", "unreadable"]
352
+ },
353
+ "limit": {
354
+ "type": "integer"
355
+ },
356
+ "usage": {
357
+ "type": "integer"
358
+ },
359
+ "byObjectType": {
360
+ "type": "array",
361
+ "items": {
362
+ "type": "object",
363
+ "required": ["objectTypeId", "limit", "usage"],
364
+ "properties": {
365
+ "objectTypeId": {
366
+ "type": "string"
367
+ },
368
+ "limit": {
369
+ "type": "integer"
370
+ },
371
+ "usage": {
372
+ "type": "integer"
373
+ }
374
+ },
375
+ "additionalProperties": false
376
+ }
377
+ },
378
+ "issue": {
379
+ "type": "string"
380
+ }
381
+ },
382
+ "additionalProperties": false,
383
+ "allOf": [
384
+ {
385
+ "if": {
386
+ "required": ["status"],
387
+ "properties": {
388
+ "status": {
389
+ "const": "read"
390
+ }
391
+ }
392
+ },
393
+ "then": {
394
+ "required": ["limit", "usage"]
395
+ }
396
+ },
397
+ {
398
+ "if": {
399
+ "required": ["status"],
400
+ "properties": {
401
+ "status": {
402
+ "const": "unreadable"
403
+ }
404
+ }
405
+ },
406
+ "then": {
407
+ "required": ["issue"]
408
+ }
409
+ }
410
+ ]
411
+ },
412
+ "step": {
413
+ "type": "object",
414
+ "required": ["id", "address", "action", "risk", "transport", "title", "expect"],
415
+ "properties": {
416
+ "id": {
417
+ "description": "s1, s2 and on, in step order.",
418
+ "type": "string",
419
+ "pattern": "^s[1-9][0-9]*$"
420
+ },
421
+ "address": {
422
+ "$ref": "#/$defs/address"
423
+ },
424
+ "action": {
425
+ "enum": ["create", "adopt", "update", "delete", "release", "manual", "unknown"]
426
+ },
427
+ "risk": {
428
+ "enum": ["safe", "risky", "destructive", "blocked", "manual"]
429
+ },
430
+ "transport": {
431
+ "description": "Open. Documented values: public-api, public-beta and runbook.",
432
+ "type": "string"
433
+ },
434
+ "api": {
435
+ "description": "The registry row's API family and pinned version.",
436
+ "type": "object",
437
+ "required": ["family", "version"],
438
+ "properties": {
439
+ "family": {
440
+ "type": "string"
441
+ },
442
+ "version": {
443
+ "type": "string"
444
+ }
445
+ },
446
+ "additionalProperties": false
447
+ },
448
+ "title": {
449
+ "description": "Human text from a fixed template, sanitized.",
450
+ "type": "string"
451
+ },
452
+ "labels": {
453
+ "description": "reverts-ui-edit: the step writes config over a value changed in HubSpot, or recreates what HubSpot no longer holds. overwrites-portal: it writes config over a value config and HubSpot never agreed on (no base). takeover: it archives what config lacks, or removes an option only the portal holds, because the mode is takeover. existed-before-kalup: a delete of an adopted resource.",
454
+ "type": "array",
455
+ "uniqueItems": true,
456
+ "items": {
457
+ "enum": ["reverts-ui-edit", "overwrites-portal", "takeover", "existed-before-kalup"]
458
+ }
459
+ },
460
+ "baseUnits": {
461
+ "description": "Units apply records in the base because config and portal already agree on them. An update's effect is its changes plus these; an update with neither only reports held units or notes, and is neither approved nor executed.",
462
+ "type": "array",
463
+ "uniqueItems": true,
464
+ "items": {
465
+ "type": "string"
466
+ }
467
+ },
468
+ "desired": {
469
+ "description": "Logical form, $ref included, resolved at apply. A create holds the full definition.",
470
+ "type": "object"
471
+ },
472
+ "ignoreChanges": {
473
+ "description": "Create only: set on create, released after.",
474
+ "type": "array",
475
+ "items": {
476
+ "type": "string"
477
+ }
478
+ },
479
+ "changes": {
480
+ "type": "array",
481
+ "items": {
482
+ "$ref": "#/$defs/change"
483
+ }
484
+ },
485
+ "held": {
486
+ "type": "array",
487
+ "items": {
488
+ "$ref": "#/$defs/held"
489
+ }
490
+ },
491
+ "notes": {
492
+ "type": "array",
493
+ "items": {
494
+ "$ref": "#/$defs/note"
495
+ }
496
+ },
497
+ "expect": {
498
+ "$ref": "#/$defs/expect"
499
+ },
500
+ "blocked": {
501
+ "$ref": "#/$defs/blocked"
502
+ },
503
+ "manual": {
504
+ "$ref": "#/$defs/manual"
505
+ },
506
+ "fulfilment": {
507
+ "$ref": "#/$defs/fulfilment"
508
+ },
509
+ "provenance": {
510
+ "$ref": "#/$defs/provenance"
511
+ }
512
+ },
513
+ "additionalProperties": false,
514
+ "allOf": [
515
+ {
516
+ "if": {
517
+ "required": ["action"],
518
+ "properties": {
519
+ "action": {
520
+ "const": "unknown"
521
+ }
522
+ }
523
+ },
524
+ "then": {
525
+ "properties": {
526
+ "risk": {
527
+ "const": "blocked"
528
+ }
529
+ }
530
+ }
531
+ },
532
+ {
533
+ "if": {
534
+ "required": ["risk"],
535
+ "properties": {
536
+ "risk": {
537
+ "const": "blocked"
538
+ }
539
+ }
540
+ },
541
+ "then": {
542
+ "required": ["blocked"]
543
+ }
544
+ },
545
+ {
546
+ "if": {
547
+ "required": ["blocked"]
548
+ },
549
+ "then": {
550
+ "properties": {
551
+ "risk": {
552
+ "const": "blocked"
553
+ }
554
+ }
555
+ }
556
+ },
557
+ {
558
+ "if": {
559
+ "required": ["action"],
560
+ "properties": {
561
+ "action": {
562
+ "const": "manual"
563
+ }
564
+ }
565
+ },
566
+ "then": {
567
+ "required": ["manual"]
568
+ }
569
+ },
570
+ {
571
+ "if": {
572
+ "required": ["action"],
573
+ "properties": {
574
+ "action": {
575
+ "enum": ["create", "adopt", "update", "delete", "unknown"]
576
+ }
577
+ }
578
+ },
579
+ "then": {
580
+ "required": ["api"]
581
+ }
582
+ },
583
+ {
584
+ "if": {
585
+ "required": ["action"],
586
+ "properties": {
587
+ "action": {
588
+ "const": "delete"
589
+ }
590
+ }
591
+ },
592
+ "then": {
593
+ "properties": {
594
+ "risk": {
595
+ "enum": ["destructive", "blocked"]
596
+ }
597
+ }
598
+ }
599
+ },
600
+ {
601
+ "if": {
602
+ "required": ["action"],
603
+ "properties": {
604
+ "action": {
605
+ "const": "release"
606
+ }
607
+ }
608
+ },
609
+ "then": {
610
+ "description": "A release drops the state entry and sends no request: no api, no values to write.",
611
+ "properties": {
612
+ "id": {},
613
+ "address": {},
614
+ "action": {},
615
+ "risk": {},
616
+ "transport": {},
617
+ "title": {},
618
+ "notes": {},
619
+ "expect": {},
620
+ "blocked": {},
621
+ "provenance": {}
622
+ },
623
+ "additionalProperties": false
624
+ }
625
+ },
626
+ {
627
+ "if": {
628
+ "required": ["action"],
629
+ "properties": {
630
+ "action": {
631
+ "const": "create"
632
+ }
633
+ }
634
+ },
635
+ "then": {
636
+ "properties": {
637
+ "expect": {
638
+ "required": ["exists"],
639
+ "properties": {
640
+ "exists": {
641
+ "const": false
642
+ }
643
+ }
644
+ }
645
+ }
646
+ }
647
+ },
648
+ {
649
+ "if": {
650
+ "required": ["action"],
651
+ "properties": {
652
+ "action": {
653
+ "enum": ["adopt", "update", "delete"]
654
+ }
655
+ }
656
+ },
657
+ "then": {
658
+ "properties": {
659
+ "expect": {
660
+ "required": ["exists"],
661
+ "properties": {
662
+ "exists": {
663
+ "const": true
664
+ }
665
+ }
666
+ }
667
+ }
668
+ }
669
+ }
670
+ ]
671
+ },
672
+ "change": {
673
+ "description": "One unit the step writes. before is the live value, after the value written. op is set for a scalar unit, add or remove for an option member.",
674
+ "type": "object",
675
+ "required": ["unit", "class", "op", "before", "after"],
676
+ "properties": {
677
+ "unit": {
678
+ "type": "string"
679
+ },
680
+ "class": {
681
+ "enum": ["config-change", "drift", "conflict", "diverged", "add", "remove"]
682
+ },
683
+ "op": {
684
+ "enum": ["set", "add", "remove"]
685
+ },
686
+ "before": {},
687
+ "after": {}
688
+ },
689
+ "additionalProperties": false
690
+ },
691
+ "held": {
692
+ "description": "A unit reported and not written, with the command that takes the portal side: a pull, or pull --accept. resolve is left out when no pull takes the portal side: the resource names a portal name a name override shadows (shadowed:<name>), or a property is outside its object's pull scope, holds a type or fieldType its builder does not take, or sits in a portal group kalup/removed.ts names; in those three cases a note on the same unit says why.",
693
+ "type": "object",
694
+ "required": ["unit", "class", "config", "live"],
695
+ "properties": {
696
+ "unit": {
697
+ "type": "string"
698
+ },
699
+ "class": {
700
+ "enum": ["drift", "conflict", "diverged"]
701
+ },
702
+ "config": {},
703
+ "live": {},
704
+ "base": {
705
+ "description": "The value config and the portal last agreed on, from state. Left out when state holds none for the unit, as for a diverged unit."
706
+ },
707
+ "resolve": {
708
+ "type": "object",
709
+ "required": ["portal"],
710
+ "properties": {
711
+ "portal": {
712
+ "type": "string"
713
+ }
714
+ },
715
+ "additionalProperties": false
716
+ }
717
+ },
718
+ "additionalProperties": false
719
+ },
720
+ "note": {
721
+ "description": "A unit kept as it is, such as a portal-only option.",
722
+ "type": "object",
723
+ "required": ["unit", "live", "note"],
724
+ "properties": {
725
+ "unit": {
726
+ "type": "string"
727
+ },
728
+ "live": {},
729
+ "note": {
730
+ "type": "string"
731
+ }
732
+ },
733
+ "additionalProperties": false
734
+ },
735
+ "expect": {
736
+ "description": "The live values the step reads or writes, checked again right before the write.",
737
+ "type": "object",
738
+ "properties": {
739
+ "exists": {
740
+ "type": "boolean"
741
+ },
742
+ "values": {
743
+ "type": "object"
744
+ },
745
+ "revisionId": {
746
+ "type": "string"
747
+ },
748
+ "baseHash": {
749
+ "$ref": "#/$defs/hash"
750
+ }
751
+ },
752
+ "additionalProperties": false
753
+ },
754
+ "blocked": {
755
+ "type": "object",
756
+ "required": ["reason", "detail", "blocks"],
757
+ "properties": {
758
+ "reason": {
759
+ "enum": [
760
+ "limit",
761
+ "scope",
762
+ "dependency-blocked",
763
+ "no-credential",
764
+ "ambiguous",
765
+ "override",
766
+ "unsupported",
767
+ "not-owned",
768
+ "policy"
769
+ ]
770
+ },
771
+ "detail": {
772
+ "type": "string"
773
+ },
774
+ "blocks": {
775
+ "description": "Addresses this block stops as dependency-blocked.",
776
+ "type": "array",
777
+ "items": {
778
+ "$ref": "#/$defs/address"
779
+ }
780
+ },
781
+ "fix": {
782
+ "type": "string"
783
+ }
784
+ },
785
+ "additionalProperties": false
786
+ },
787
+ "manual": {
788
+ "description": "A runbook step for a person, in HubSpot UI wording.",
789
+ "type": "object",
790
+ "required": ["url", "instructions", "verify"],
791
+ "properties": {
792
+ "url": {
793
+ "type": "string"
794
+ },
795
+ "instructions": {
796
+ "type": "array",
797
+ "items": {
798
+ "type": "string"
799
+ }
800
+ },
801
+ "verify": {
802
+ "type": "object",
803
+ "required": ["kind"],
804
+ "properties": {
805
+ "kind": {
806
+ "enum": ["read-back", "human-confirm"]
807
+ },
808
+ "prompt": {
809
+ "type": "string"
810
+ }
811
+ },
812
+ "additionalProperties": false,
813
+ "if": {
814
+ "required": ["kind"],
815
+ "properties": {
816
+ "kind": {
817
+ "const": "human-confirm"
818
+ }
819
+ }
820
+ },
821
+ "then": {
822
+ "required": ["prompt"]
823
+ }
824
+ }
825
+ },
826
+ "additionalProperties": false
827
+ },
828
+ "fulfilment": {
829
+ "description": "A registered executor that fulfils a runbook step, and the hash of its disclosure text.",
830
+ "type": "object",
831
+ "required": ["executor", "disclosure"],
832
+ "properties": {
833
+ "executor": {
834
+ "description": "<id>@<version>.",
835
+ "type": "string",
836
+ "pattern": "^\\S+@[^@\\s]+$"
837
+ },
838
+ "disclosure": {
839
+ "$ref": "#/$defs/hash"
840
+ }
841
+ },
842
+ "additionalProperties": false
843
+ },
844
+ "provenance": {
845
+ "description": "The blueprint a resource came from, as in the IR.",
846
+ "type": "object",
847
+ "required": ["blueprint", "version", "sourceAddress", "prefix", "hash"],
848
+ "properties": {
849
+ "blueprint": {
850
+ "type": "string"
851
+ },
852
+ "version": {
853
+ "type": "string"
854
+ },
855
+ "sourceAddress": {
856
+ "$ref": "#/$defs/address"
857
+ },
858
+ "prefix": {
859
+ "type": "string"
860
+ },
861
+ "hash": {
862
+ "type": "string"
863
+ }
864
+ },
865
+ "additionalProperties": false
866
+ }
867
+ }
868
+ }