@highstate/backend 0.19.1 → 0.20.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 (120) hide show
  1. package/dist/{chunk-V2NILDHS.js → chunk-52MY2TCE.js} +347 -19
  2. package/dist/chunk-52MY2TCE.js.map +1 -0
  3. package/dist/{chunk-I7BWSAN6.js → chunk-UAWBPTDW.js} +3 -3
  4. package/dist/{chunk-I7BWSAN6.js.map → chunk-UAWBPTDW.js.map} +1 -1
  5. package/dist/highstate.manifest.json +4 -4
  6. package/dist/index.js +4159 -785
  7. package/dist/index.js.map +1 -1
  8. package/dist/library/worker/main.js +5 -2
  9. package/dist/library/worker/main.js.map +1 -1
  10. package/dist/shared/index.js +2 -2
  11. package/package.json +7 -7
  12. package/prisma/backend/_schema/object.prisma +12 -0
  13. package/prisma/backend/sqlite/migrations/20260222113554_add_object_tracking/migration.sql +7 -0
  14. package/prisma/project/artifact.prisma +3 -0
  15. package/prisma/project/entity.prisma +125 -0
  16. package/prisma/project/instance.prisma +6 -0
  17. package/prisma/project/migrations/20260301210131_add_entity_tracking/migration.sql +70 -0
  18. package/prisma/project/migrations/20260302212734_add_resource_hooks_flag/migration.sql +1 -0
  19. package/prisma/project/operation.prisma +3 -0
  20. package/src/business/artifact.test.ts +22 -2
  21. package/src/business/artifact.ts +7 -1
  22. package/src/business/entity-snapshot.test.ts +684 -0
  23. package/src/business/entity-snapshot.ts +904 -0
  24. package/src/business/evaluation.test.ts +56 -0
  25. package/src/business/evaluation.ts +102 -22
  26. package/src/business/global-search.test.ts +344 -0
  27. package/src/business/global-search.ts +902 -0
  28. package/src/business/index.ts +4 -0
  29. package/src/business/instance-lock.ts +58 -74
  30. package/src/business/instance-state.test.ts +15 -1
  31. package/src/business/instance-state.ts +37 -14
  32. package/src/business/object-ref-index.test.ts +140 -0
  33. package/src/business/object-ref-index.ts +193 -0
  34. package/src/business/operation.test.ts +15 -1
  35. package/src/business/operation.ts +4 -0
  36. package/src/business/project-model.ts +154 -13
  37. package/src/business/project-unlock.ts +25 -2
  38. package/src/business/project.ts +9 -0
  39. package/src/business/secret.test.ts +35 -2
  40. package/src/business/secret.ts +32 -9
  41. package/src/business/settings.ts +761 -0
  42. package/src/business/unit-output.test.ts +477 -0
  43. package/src/business/unit-output.ts +461 -0
  44. package/src/business/worker.ts +55 -4
  45. package/src/database/_generated/backend/postgresql/browser.ts +6 -0
  46. package/src/database/_generated/backend/postgresql/client.ts +6 -0
  47. package/src/database/_generated/backend/postgresql/internal/class.ts +23 -5
  48. package/src/database/_generated/backend/postgresql/internal/prismaNamespace.ts +89 -5
  49. package/src/database/_generated/backend/postgresql/internal/prismaNamespaceBrowser.ts +9 -0
  50. package/src/database/_generated/backend/postgresql/models/Object.ts +1076 -0
  51. package/src/database/_generated/backend/postgresql/models.ts +1 -0
  52. package/src/database/_generated/backend/sqlite/browser.ts +6 -0
  53. package/src/database/_generated/backend/sqlite/client.ts +6 -0
  54. package/src/database/_generated/backend/sqlite/internal/class.ts +23 -5
  55. package/src/database/_generated/backend/sqlite/internal/prismaNamespace.ts +89 -5
  56. package/src/database/_generated/backend/sqlite/internal/prismaNamespaceBrowser.ts +9 -0
  57. package/src/database/_generated/backend/sqlite/models/Object.ts +1074 -0
  58. package/src/database/_generated/backend/sqlite/models.ts +1 -0
  59. package/src/database/_generated/project/browser.ts +23 -0
  60. package/src/database/_generated/project/client.ts +23 -0
  61. package/src/database/_generated/project/commonInputTypes.ts +87 -53
  62. package/src/database/_generated/project/enums.ts +8 -0
  63. package/src/database/_generated/project/internal/class.ts +53 -5
  64. package/src/database/_generated/project/internal/prismaNamespace.ts +367 -13
  65. package/src/database/_generated/project/internal/prismaNamespaceBrowser.ts +48 -1
  66. package/src/database/_generated/project/models/Artifact.ts +199 -11
  67. package/src/database/_generated/project/models/Entity.ts +1274 -0
  68. package/src/database/_generated/project/models/EntitySnapshot.ts +2389 -0
  69. package/src/database/_generated/project/models/EntitySnapshotContent.ts +1260 -0
  70. package/src/database/_generated/project/models/EntitySnapshotReference.ts +1449 -0
  71. package/src/database/_generated/project/models/InstanceState.ts +361 -1
  72. package/src/database/_generated/project/models/Operation.ts +148 -3
  73. package/src/database/_generated/project/models/OperationLog.ts +0 -4
  74. package/src/database/_generated/project/models.ts +4 -0
  75. package/src/database/migration.ts +3 -0
  76. package/src/library/worker/evaluator.ts +7 -1
  77. package/src/orchestrator/manager.ts +7 -0
  78. package/src/orchestrator/operation-context.captured-outputs.test.ts +118 -0
  79. package/src/orchestrator/operation-context.ts +154 -16
  80. package/src/orchestrator/operation-plan.destroy.test.md +33 -12
  81. package/src/orchestrator/operation-plan.destroy.test.ts +140 -2
  82. package/src/orchestrator/operation-plan.fixtures.ts +2 -0
  83. package/src/orchestrator/operation-plan.md +4 -1
  84. package/src/orchestrator/operation-plan.ts +286 -92
  85. package/src/orchestrator/operation-plan.update.test.md +286 -11
  86. package/src/orchestrator/operation-plan.update.test.ts +656 -5
  87. package/src/orchestrator/operation-workset.ts +72 -22
  88. package/src/orchestrator/operation.cancel.test.ts +4 -0
  89. package/src/orchestrator/operation.composite.test.ts +341 -0
  90. package/src/orchestrator/operation.destroy.test.ts +4 -0
  91. package/src/orchestrator/operation.output-validation.failure.test.ts +124 -0
  92. package/src/orchestrator/operation.preview.test.ts +4 -0
  93. package/src/orchestrator/operation.refresh.test.ts +4 -0
  94. package/src/orchestrator/operation.test-utils.ts +52 -13
  95. package/src/orchestrator/operation.ts +228 -68
  96. package/src/orchestrator/operation.update.failure.test.ts +4 -0
  97. package/src/orchestrator/operation.update.skip.test.ts +110 -0
  98. package/src/orchestrator/operation.update.test.ts +4 -0
  99. package/src/orchestrator/plan-test-builder.ts +1 -0
  100. package/src/orchestrator/unit-input-values.test.ts +450 -0
  101. package/src/orchestrator/unit-input-values.ts +281 -0
  102. package/src/pubsub/manager.ts +3 -0
  103. package/src/runner/abstractions.ts +23 -54
  104. package/src/runner/local.ts +109 -85
  105. package/src/services.ts +52 -1
  106. package/src/shared/models/prisma.ts +1 -0
  107. package/src/shared/models/project/entity.ts +121 -0
  108. package/src/shared/models/project/index.ts +1 -0
  109. package/src/shared/models/project/operation.ts +61 -3
  110. package/src/shared/models/project/state.ts +10 -0
  111. package/src/shared/models/project/worker.ts +7 -0
  112. package/src/shared/resolvers/effective-output-type.test.ts +494 -0
  113. package/src/shared/resolvers/effective-output-type.ts +162 -0
  114. package/src/shared/resolvers/index.ts +1 -0
  115. package/src/shared/resolvers/input.ts +59 -9
  116. package/src/shared/utils/index.ts +1 -0
  117. package/src/shared/utils/stable-json.ts +41 -0
  118. package/src/terminal/manager.ts +6 -0
  119. package/src/worker/manager.ts +97 -1
  120. package/dist/chunk-V2NILDHS.js.map +0 -1
@@ -30,9 +30,84 @@ graph RL
30
30
 
31
31
  **Update Phase**: `B`, `C`
32
32
 
33
- ### Example 2: Composite Boundary Isolation
33
+ ### Example 1a: Ignore Changed Dependencies Only
34
34
 
35
- **Test**: `should not propagate beyond compositional inclusion`
35
+ **Test**: `should skip only changed dependencies when ignoreChangedDependencies enabled`
36
+
37
+ ```mermaid
38
+ graph RL
39
+ A["A ✅"]
40
+ B["B ≠"]
41
+ C["C 🚀"]
42
+
43
+ C --> B --> A
44
+ ```
45
+
46
+ **Options:**
47
+
48
+ - `ignoreChangedDependencies`: `true`
49
+
50
+ **Decision Steps**:
51
+
52
+ 1. `C` explicitly requested;
53
+ 2. `C` depends on `B`, `B` is only changed and changed dependencies are ignored → `B` excluded;
54
+ 3. no failed/undeployed prerequisite is present in this chain.
55
+
56
+ **Update Phase**: `C`
57
+
58
+ ### Example 1b: Ignore Changed But Keep Undeployed/Failed
59
+
60
+ **Test**: `should still include undeployed dependencies when ignoreChangedDependencies enabled`
61
+
62
+ ```mermaid
63
+ graph RL
64
+ A["A ≠"]
65
+ B["B ∅"]
66
+ C["C 🚀"]
67
+
68
+ C --> B --> A
69
+ ```
70
+
71
+ **Options:**
72
+
73
+ - `ignoreChangedDependencies`: `true`
74
+
75
+ **Decision Steps**:
76
+
77
+ 1. `C` explicitly requested;
78
+ 2. `C` depends on `B`, `B` is undeployed → `B` included for safety;
79
+ 3. `B` depends on `A`, `A` is only changed and changed dependencies are ignored → `A` excluded.
80
+
81
+ **Update Phase**: `B`, `C`
82
+
83
+ ### Example 1c: Manual Ignore All Dependencies
84
+
85
+ **Test**: `should ignore all dependencies when ignoreDependencies enabled`
86
+
87
+ ```mermaid
88
+ graph RL
89
+ A["A ≠"]
90
+ B["B ∅"]
91
+ C["C 🚀"]
92
+
93
+ C --> B --> A
94
+ ```
95
+
96
+ **Options:**
97
+
98
+ - `ignoreDependencies`: `true`
99
+
100
+ **Decision Steps**:
101
+
102
+ 1. `C` explicitly requested;
103
+ 2. `C` dependencies are fully ignored in manual mode;
104
+ 3. both changed and undeployed prerequisites are skipped.
105
+
106
+ **Update Phase**: `C`
107
+
108
+ ### Example 2: Full Ancestor Chain for Compositional Inclusion
109
+
110
+ **Test**: `should include full ancestor chain for compositional inclusion`
36
111
 
37
112
  ```mermaid
38
113
  graph RL
@@ -52,10 +127,10 @@ graph RL
52
127
  1. `B` explicitly requested;
53
128
  2. `B` depends on `A`, `A` is outdated → `A` included;
54
129
  3. `A` is child of `Parent` → `Parent` included (compositional);
55
- 4. `Parent` is child of `GrandParent` → `GrandParent` NOT included (compositional boundary);
56
- 5. `C` is sibling of `Parent`, `C` is outdated but `GrandParent` is not included → `C` NOT included.
130
+ 4. `Parent` is child of `GrandParent` → `GrandParent` included as ancestor;
131
+ 5. `C` is sibling of `Parent`, but ancestor inclusion does not auto-include siblings → `C` NOT included.
57
132
 
58
- **Update Phase**: `A`, `Parent`, `B`
133
+ **Update Phase**: `A`, `Parent`, `GrandParent`, `B`
59
134
 
60
135
  ### Example 3: Force Dependencies
61
136
 
@@ -124,6 +199,157 @@ graph RL
124
199
 
125
200
  **Destroy Phase**: `GhostChild`, `Parent`
126
201
 
202
+ ### Example 5a: Force Children With Ghost-Only Composite
203
+
204
+ **Test**: `should cleanup ghost children when forceUpdateChildren is enabled`
205
+
206
+ ```mermaid
207
+ graph RL
208
+ subgraph Parent["Parent 🚀"]
209
+ GhostChild["GhostChild 👻"]
210
+ end
211
+ ```
212
+
213
+ **Options:**
214
+
215
+ - `forceUpdateChildren`: `true`
216
+
217
+ **Decision Steps**:
218
+
219
+ 1. `Parent` explicitly requested;
220
+ 2. `forceUpdateChildren` applies to real children only, so `GhostChild` is not included in update phase;
221
+ 3. `Parent` has no non-ghost child that needs update, so update phase stays empty;
222
+ 4. ghost cleanup pass includes `GhostChild` in destroy phase;
223
+ 5. `Parent` is added to destroy phase as parent of destroyed ghost child.
224
+
225
+ **Destroy Phase**: `GhostChild`, `Parent`
226
+
227
+ ### Example 5b: Nested Ghost Cleanup for Child Composites
228
+
229
+ **Test**: `should cleanup ghosts from nested child composites during parent composite update`
230
+
231
+ ```mermaid
232
+ graph RL
233
+ subgraph Parent["Parent 🚀"]
234
+ subgraph ChildComposite["ChildComposite ✅"]
235
+ GhostLeaf["GhostLeaf 👻"]
236
+ end
237
+ end
238
+ ```
239
+
240
+ **Decision Steps**:
241
+
242
+ 1. `Parent` explicitly requested;
243
+ 2. no non-ghost outdated descendants exist, so update phase is empty;
244
+ 3. ghost cleanup traverses the full composite subtree, not only direct children;
245
+ 4. nested `GhostLeaf` is included in destroy phase;
246
+ 5. intermediate composite chain needed for state recalculation is included, so `ChildComposite` and `Parent` are also added to destroy phase.
247
+
248
+ **Destroy Phase**: `GhostLeaf`, `ChildComposite`, `Parent`
249
+
250
+ ### Example 5c: Only Destroy Ghosts
251
+
252
+ **Test**: `should run only ghost destroy phase when onlyDestroyGhosts is enabled`
253
+
254
+ ```mermaid
255
+ graph RL
256
+ subgraph Parent["Parent 🚀"]
257
+ Child1["Child1 ≠"]
258
+ GhostChild["GhostChild 👻"]
259
+ end
260
+ ```
261
+
262
+ **Options:**
263
+
264
+ - `onlyDestroyGhosts`: `true`
265
+
266
+ **Decision Steps**:
267
+
268
+ 1. `Parent` explicitly requested;
269
+ 2. `Child1` is outdated and would normally be included in update phase;
270
+ 3. `onlyDestroyGhosts` disables update phase generation entirely;
271
+ 4. ghost cleanup still runs and includes `GhostChild`;
272
+ 5. `Parent` is included in destroy phase as parent of destroyed ghost child.
273
+
274
+ **Destroy Phase**: `GhostChild`, `Parent`
275
+
276
+ ### Example 5d: Destroy Ghosts Before Update
277
+
278
+ **Test**: `should place ghost destroy phase before update when firstDestroyGhosts is enabled`
279
+
280
+ ```mermaid
281
+ graph RL
282
+ subgraph Parent["Parent 🚀"]
283
+ Child1["Child1 ≠"]
284
+ GhostChild["GhostChild 👻"]
285
+ end
286
+ ```
287
+
288
+ **Options:**
289
+
290
+ - `firstDestroyGhosts`: `true`
291
+
292
+ **Decision Steps**:
293
+
294
+ 1. `Parent` explicitly requested;
295
+ 2. `Child1` is outdated and included in update phase;
296
+ 3. `GhostChild` is included in ghost cleanup destroy phase;
297
+ 4. option reorders phases so destroy runs before update;
298
+ 5. both phases are kept.
299
+
300
+ **Destroy Phase**: `GhostChild`, `Parent`
301
+
302
+ **Update Phase**: `Child1`, `Parent`
303
+
304
+ ### Example 5e: Ignore Ghost Cleanup
305
+
306
+ **Test**: `should skip ghost destroy phase when ignoreGhosts is enabled`
307
+
308
+ ```mermaid
309
+ graph RL
310
+ subgraph Parent["Parent 🚀"]
311
+ Child1["Child1 ≠"]
312
+ GhostChild["GhostChild 👻"]
313
+ end
314
+ ```
315
+
316
+ **Options:**
317
+
318
+ - `ignoreGhosts`: `true`
319
+
320
+ **Decision Steps**:
321
+
322
+ 1. `Parent` explicitly requested;
323
+ 2. `Child1` is outdated and included in update phase;
324
+ 3. ghost cleanup generation is disabled by `ignoreGhosts`;
325
+ 4. no destroy phase is created for ghosts.
326
+
327
+ **Update Phase**: `Child1`, `Parent`
328
+
329
+ ### Example 5f: Mutually Exclusive Ghost Strategy Options
330
+
331
+ **Test**: `should reject mutually exclusive ghost options`
332
+
333
+ ```mermaid
334
+ graph RL
335
+ subgraph Parent["Parent 🚀"]
336
+ GhostChild["GhostChild 👻"]
337
+ end
338
+ ```
339
+
340
+ **Options:**
341
+
342
+ - `onlyDestroyGhosts`: `true`
343
+ - `ignoreGhosts`: `true`
344
+
345
+ **Decision Steps**:
346
+
347
+ 1. planner validates ghost strategy options before phase construction;
348
+ 2. more than one of `onlyDestroyGhosts`, `firstDestroyGhosts`, `ignoreGhosts` is enabled;
349
+ 3. operation plan creation is rejected as invalid.
350
+
351
+ **Result**: validation error
352
+
127
353
  ### Example 6: Nested Composites with Mixed Updates
128
354
 
129
355
  **Test**: `should handle complex nested hierarchy correctly`
@@ -293,9 +519,9 @@ graph RL
293
519
 
294
520
  **Update Phase**: `A`, `C`
295
521
 
296
- ### Example 13: Deep Nesting with Boundary Isolation
522
+ ### Example 13: Deep Nesting with Ancestor Chain Inclusion
297
523
 
298
- **Test**: `should isolate boundaries in deep composite hierarchies`
524
+ **Test**: `should include deep ancestor chain without ancestor siblings`
299
525
 
300
526
  ```mermaid
301
527
  graph RL
@@ -314,10 +540,11 @@ graph RL
314
540
 
315
541
  1. `Child` explicitly requested;
316
542
  2. `Child` is child of `Parent` → `Parent` included (compositional);
317
- 3. `Parent` is child of `GrandParent` → `GrandParent` NOT included (compositional boundary);
318
- 4. `Uncle` and `GreatUncle` not affected.
543
+ 3. `Parent` is child of `GrandParent` → `GrandParent` included as ancestor;
544
+ 4. `GrandParent` is child of `GreatGrandParent` `GreatGrandParent` included as ancestor;
545
+ 5. `Uncle` and `GreatUncle` are ancestor siblings and are not auto-included.
319
546
 
320
- **Update Phase**: `Child`, `Parent`
547
+ **Update Phase**: `Child`, `Parent`, `GrandParent`, `GreatGrandParent`
321
548
 
322
549
  ### Example 14: Mixed Force Flags
323
550
 
@@ -469,7 +696,7 @@ graph RL
469
696
  Child3["Child3 ≠"]
470
697
  Child4["Child4 ≠"]
471
698
  end
472
-
699
+
473
700
  Child2 --> Child1
474
701
  Child3 --> Child4
475
702
  ```
@@ -483,3 +710,51 @@ graph RL
483
710
  5. `Child4` is child of compositional composite, outdated → `Child4` excluded (rule 3 doesn't apply).
484
711
 
485
712
  **Update Phase**: `Child1`, `Child2`, `Parent`
713
+
714
+ ### Example 20: Explicit Empty Nested Composite
715
+
716
+ **Test**: `should skip explicitly requested empty nested composites`
717
+
718
+ ```mermaid
719
+ graph RL
720
+ subgraph Root["Root 🚀"]
721
+ subgraph Level1["Level1 ✅"]
722
+ Level2["Level2 ✅"]
723
+ end
724
+ end
725
+ ```
726
+
727
+ **Decision Steps**:
728
+
729
+ 1. `Root` explicitly requested;
730
+ 2. `Root` has no unit descendants (directly or recursively) → empty composite;
731
+ 3. empty composites are not added to operation plan;
732
+ 4. `Level1` and `Level2` are also empty composites and remain excluded.
733
+
734
+ **Update Phase**: _(empty)_
735
+
736
+ ### Example 21: Mixed Nested Branches with Empty Composite Pruning
737
+
738
+ **Test**: `should keep non-empty branch while skipping empty nested composites`
739
+
740
+ ```mermaid
741
+ graph RL
742
+ subgraph Root["Root 🚀"]
743
+ subgraph EmptyLevel1
744
+ EmptyLevel2["EmptyLevel2 ✅"]
745
+ end
746
+ subgraph NonEmptyLevel1
747
+ Leaf["Leaf ≠"]
748
+ end
749
+ end
750
+ ```
751
+
752
+ **Decision Steps**:
753
+
754
+ 1. `Root` explicitly requested;
755
+ 2. `EmptyLevel1`/`EmptyLevel2` have no unit descendants → both excluded;
756
+ 3. `Leaf` is outdated and is a unit descendant under `NonEmptyLevel1` → `Leaf` included;
757
+ 4. `NonEmptyLevel1` is parent of included child → `NonEmptyLevel1` included;
758
+ 5. `Root` is explicitly requested and non-empty due to `Leaf` branch → `Root` included.
759
+
760
+ **Update Phase**: `Root`, `Leaf`, `NonEmptyLevel1`