@reventlessdev/reventless-core 3.0.0-alpha.273 → 3.0.0-alpha.275
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/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.275 (2026-09-25)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **spec,core:** a partition tag its chapter backs overrides inference ([4244a4a](https://github.com/ReventlessDev/reventless-core/commit/4244a4af9e7aad4378d9b6276ddeb44878e125b2))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# 3.0.0-alpha.274 (2026-09-24)
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **dcb:** a command reference no decision reads by stays out of the query ([3ae149a](https://github.com/ReventlessDev/reventless-core/commit/3ae149ae91ebab63413be57df5827c5fd4390160))
|
|
18
|
+
|
|
19
|
+
|
|
6
20
|
# 3.0.0-alpha.273 (2026-09-24)
|
|
7
21
|
|
|
8
22
|
### Features
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-core",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.275",
|
|
4
4
|
"description": "Core package for Reventless framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.22",
|
|
37
37
|
"@reventlessdev/rescript-ssh2": "2.0.0-alpha.15",
|
|
38
38
|
"@reventlessdev/rescript-uuid": "2.0.0-alpha.1",
|
|
39
|
-
"@reventlessdev/reventless-infra": "3.0.0-alpha.
|
|
40
|
-
"@reventlessdev/reventless-
|
|
41
|
-
"@reventlessdev/reventless-
|
|
39
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.175",
|
|
40
|
+
"@reventlessdev/reventless-interop": "3.0.0-alpha.38",
|
|
41
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.147"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"rescript": "12.3.1",
|
|
45
45
|
"sury-ppx": "11.0.0",
|
|
46
|
-
"@reventlessdev/reventless-ppx": "1.0.0-alpha.
|
|
46
|
+
"@reventlessdev/reventless-ppx": "1.0.0-alpha.94"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"rescript": "^12.3.1"
|
|
@@ -237,11 +237,14 @@ module Make = (
|
|
|
237
237
|
|
|
238
238
|
// A `@partitionTag` inference contradicts would steer storage, fence and read
|
|
239
239
|
// scope to a key the slice only references, so it stops the build. One that
|
|
240
|
-
// inference agrees with is noise, and says so.
|
|
240
|
+
// inference agrees with is noise, and says so. One its chapter backs against
|
|
241
|
+
// inference is the author deciding what inference cannot see, and is kept.
|
|
241
242
|
let hintIssues = Reventless.DcbValidation.validatePartitionHintsVsInference(
|
|
242
243
|
~shapes=inferenceShapes,
|
|
243
244
|
)
|
|
244
|
-
hintIssues.redundancies
|
|
245
|
+
hintIssues.redundancies
|
|
246
|
+
->Array.concat(hintIssues.overrides)
|
|
247
|
+
->Array.forEach(e =>
|
|
245
248
|
log.info(~comp="Dcb_Builder", `DCB partition (${e.sliceName}): ${e.message}`)
|
|
246
249
|
)
|
|
247
250
|
if hintIssues.contradictions->Array.length > 0 {
|
|
@@ -178,7 +178,7 @@ function Make(DcbEventLogStorage) {
|
|
|
178
178
|
}));
|
|
179
179
|
let inferenceShapes = sliceSchemas.map(DcbTag$Reventless.sliceShape);
|
|
180
180
|
let hintIssues = DcbValidation$Reventless.validatePartitionHintsVsInference(inferenceShapes);
|
|
181
|
-
hintIssues.redundancies.forEach(e => log.info("Dcb_Builder", undefined, `DCB partition (` + e.sliceName + `): ` + e.message));
|
|
181
|
+
hintIssues.redundancies.concat(hintIssues.overrides).forEach(e => log.info("Dcb_Builder", undefined, `DCB partition (` + e.sliceName + `): ` + e.message));
|
|
182
182
|
if (hintIssues.contradictions.length !== 0) {
|
|
183
183
|
let detail = hintIssues.contradictions.map(e => e.sliceName + `: ` + e.message).join(" | ");
|
|
184
184
|
log.error("Dcb_Builder", undefined, `DCB partition contradiction (` + name + `): ` + detail);
|
|
@@ -503,6 +503,80 @@ describe("DcbScopeInference:", () => {
|
|
|
503
503
|
expect(issues.redundancies)->toEqual([])
|
|
504
504
|
},
|
|
505
505
|
)
|
|
506
|
+
|
|
507
|
+
// `ShipOrder` records the carrier's booking, which nothing else in the boundary
|
|
508
|
+
// writes or reads. Rule 1 subtracts `orderId` (read off `OrderPlaced`) and is
|
|
509
|
+
// left with the booking: `AddProduct`'s shape exactly, with the other answer.
|
|
510
|
+
let placeOrder = slice(
|
|
511
|
+
"PlaceOrder",
|
|
512
|
+
~chapter="Order",
|
|
513
|
+
~produced=[ev("OrderPlaced", [scal("orderId")])],
|
|
514
|
+
)
|
|
515
|
+
let shipOrder = slice(
|
|
516
|
+
"ShipOrder",
|
|
517
|
+
~chapter="Order",
|
|
518
|
+
~partitionHint="orderId",
|
|
519
|
+
~command=[scal("orderId"), scal("carrierBookingId")],
|
|
520
|
+
~consumed=[ev("OrderPlaced", [scal("orderId")]), ev("OrderShipped", [scal("orderId")])],
|
|
521
|
+
~produced=[ev("OrderShipped", [scal("orderId"), scal("carrierBookingId")])],
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
testSync(
|
|
525
|
+
"a hint its chapter backs overrides inference instead of contradicting it",
|
|
526
|
+
() => {
|
|
527
|
+
let issues = check([placeOrder, shipOrder])
|
|
528
|
+
expect(issues.contradictions)->toEqual([])
|
|
529
|
+
expect(issues.redundancies)->toEqual([])
|
|
530
|
+
expect(issues.overrides->names)->toEqual(["ShipOrder"])
|
|
531
|
+
// and the hint is what the boundary is partitioned by
|
|
532
|
+
expect(
|
|
533
|
+
DSI.resolvePartitions([placeOrder, shipOrder]).partitionBySlice->Dict.get("ShipOrder"),
|
|
534
|
+
)->toEqual(Some("orderId"))
|
|
535
|
+
},
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
testSync(
|
|
539
|
+
"without a chapter the same hint is still a contradiction",
|
|
540
|
+
() => {
|
|
541
|
+
let noChapter = (s: DSI.sliceShape) => {...s, chapter: ?None}
|
|
542
|
+
let issues = check([noChapter(placeOrder), noChapter(shipOrder)])
|
|
543
|
+
expect(issues.contradictions->names)->toEqual(["ShipOrder"])
|
|
544
|
+
expect(issues.overrides)->toEqual([])
|
|
545
|
+
},
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
testSync(
|
|
549
|
+
"a hint its chapter disagrees with is still a contradiction",
|
|
550
|
+
() => {
|
|
551
|
+
// Every event under `Product/` carries `productId`, not `categoryId`.
|
|
552
|
+
let inProduct = {...hinted(addProduct, "categoryId"), chapter: "Product"}
|
|
553
|
+
let issues = check([inProduct, {...addCategory, chapter: "Category"}])
|
|
554
|
+
expect(issues.contradictions->names)->toEqual(["AddProduct"])
|
|
555
|
+
expect(issues.overrides)->toEqual([])
|
|
556
|
+
},
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
testSync(
|
|
560
|
+
"a chapter-backed hint read off another entity's events is still a contradiction",
|
|
561
|
+
() => {
|
|
562
|
+
// `WarehouseAssigned` carries the order but belongs to the warehouse.
|
|
563
|
+
let assign = slice(
|
|
564
|
+
"AssignWarehouse",
|
|
565
|
+
~chapter="Warehouse",
|
|
566
|
+
~partitionHint="warehouseId",
|
|
567
|
+
~produced=[ev("WarehouseAssigned", [scal("warehouseId"), scal("orderId")])],
|
|
568
|
+
)
|
|
569
|
+
let ship = {
|
|
570
|
+
...shipOrder,
|
|
571
|
+
consumed: shipOrder.consumed->Array.concat([
|
|
572
|
+
ev("WarehouseAssigned", [scal("warehouseId"), scal("orderId")]),
|
|
573
|
+
]),
|
|
574
|
+
}
|
|
575
|
+
let issues = check([placeOrder, ship, assign])
|
|
576
|
+
expect(issues.overrides->names)->toEqual([])
|
|
577
|
+
expect(issues.contradictions->names)->toEqual(["ShipOrder"])
|
|
578
|
+
},
|
|
579
|
+
)
|
|
506
580
|
})
|
|
507
581
|
|
|
508
582
|
describe("ambiguity surfacing", () => {
|
|
@@ -814,6 +814,123 @@ globalThis.describe("DcbScopeInference:", () => {
|
|
|
814
814
|
globalThis.expect(issues.contradictions).toEqual([]);
|
|
815
815
|
globalThis.expect(issues.redundancies).toEqual([]);
|
|
816
816
|
});
|
|
817
|
+
let placeOrder = slice("PlaceOrder", undefined, undefined, [{
|
|
818
|
+
eventType: "OrderPlaced",
|
|
819
|
+
idFields: [{
|
|
820
|
+
name: "orderId",
|
|
821
|
+
isList: false
|
|
822
|
+
}]
|
|
823
|
+
}], undefined, "Order");
|
|
824
|
+
let shipOrder = slice("ShipOrder", [
|
|
825
|
+
{
|
|
826
|
+
name: "orderId",
|
|
827
|
+
isList: false
|
|
828
|
+
},
|
|
829
|
+
{
|
|
830
|
+
name: "carrierBookingId",
|
|
831
|
+
isList: false
|
|
832
|
+
}
|
|
833
|
+
], [
|
|
834
|
+
{
|
|
835
|
+
eventType: "OrderPlaced",
|
|
836
|
+
idFields: [{
|
|
837
|
+
name: "orderId",
|
|
838
|
+
isList: false
|
|
839
|
+
}]
|
|
840
|
+
},
|
|
841
|
+
{
|
|
842
|
+
eventType: "OrderShipped",
|
|
843
|
+
idFields: [{
|
|
844
|
+
name: "orderId",
|
|
845
|
+
isList: false
|
|
846
|
+
}]
|
|
847
|
+
}
|
|
848
|
+
], [{
|
|
849
|
+
eventType: "OrderShipped",
|
|
850
|
+
idFields: [
|
|
851
|
+
{
|
|
852
|
+
name: "orderId",
|
|
853
|
+
isList: false
|
|
854
|
+
},
|
|
855
|
+
{
|
|
856
|
+
name: "carrierBookingId",
|
|
857
|
+
isList: false
|
|
858
|
+
}
|
|
859
|
+
]
|
|
860
|
+
}], "orderId", "Order");
|
|
861
|
+
globalThis.test("a hint its chapter backs overrides inference instead of contradicting it", () => {
|
|
862
|
+
let issues = DcbValidation$Reventless.validatePartitionHintsVsInference([
|
|
863
|
+
placeOrder,
|
|
864
|
+
shipOrder
|
|
865
|
+
]);
|
|
866
|
+
globalThis.expect(issues.contradictions).toEqual([]);
|
|
867
|
+
globalThis.expect(issues.redundancies).toEqual([]);
|
|
868
|
+
globalThis.expect(issues.overrides.map(e => e.sliceName)).toEqual(["ShipOrder"]);
|
|
869
|
+
globalThis.expect(DcbScopeInference$Reventless.resolvePartitions([
|
|
870
|
+
placeOrder,
|
|
871
|
+
shipOrder
|
|
872
|
+
]).partitionBySlice["ShipOrder"]).toEqual("orderId");
|
|
873
|
+
});
|
|
874
|
+
globalThis.test("without a chapter the same hint is still a contradiction", () => {
|
|
875
|
+
let noChapter = s => {
|
|
876
|
+
let newrecord = {...s};
|
|
877
|
+
newrecord.chapter = undefined;
|
|
878
|
+
return newrecord;
|
|
879
|
+
};
|
|
880
|
+
let issues = DcbValidation$Reventless.validatePartitionHintsVsInference([
|
|
881
|
+
noChapter(placeOrder),
|
|
882
|
+
noChapter(shipOrder)
|
|
883
|
+
]);
|
|
884
|
+
globalThis.expect(issues.contradictions.map(e => e.sliceName)).toEqual(["ShipOrder"]);
|
|
885
|
+
globalThis.expect(issues.overrides).toEqual([]);
|
|
886
|
+
});
|
|
887
|
+
globalThis.test("a hint its chapter disagrees with is still a contradiction", () => {
|
|
888
|
+
let newrecord = {...hinted(addProduct, "categoryId")};
|
|
889
|
+
newrecord.chapter = "Product";
|
|
890
|
+
let newrecord$1 = {...addCategory};
|
|
891
|
+
let issues = DcbValidation$Reventless.validatePartitionHintsVsInference([
|
|
892
|
+
newrecord,
|
|
893
|
+
(newrecord$1.chapter = "Category", newrecord$1)
|
|
894
|
+
]);
|
|
895
|
+
globalThis.expect(issues.contradictions.map(e => e.sliceName)).toEqual(["AddProduct"]);
|
|
896
|
+
globalThis.expect(issues.overrides).toEqual([]);
|
|
897
|
+
});
|
|
898
|
+
globalThis.test("a chapter-backed hint read off another entity's events is still a contradiction", () => {
|
|
899
|
+
let assign = slice("AssignWarehouse", undefined, undefined, [{
|
|
900
|
+
eventType: "WarehouseAssigned",
|
|
901
|
+
idFields: [
|
|
902
|
+
{
|
|
903
|
+
name: "warehouseId",
|
|
904
|
+
isList: false
|
|
905
|
+
},
|
|
906
|
+
{
|
|
907
|
+
name: "orderId",
|
|
908
|
+
isList: false
|
|
909
|
+
}
|
|
910
|
+
]
|
|
911
|
+
}], "warehouseId", "Warehouse");
|
|
912
|
+
let newrecord = {...shipOrder};
|
|
913
|
+
newrecord.consumed = shipOrder.consumed.concat([{
|
|
914
|
+
eventType: "WarehouseAssigned",
|
|
915
|
+
idFields: [
|
|
916
|
+
{
|
|
917
|
+
name: "warehouseId",
|
|
918
|
+
isList: false
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
name: "orderId",
|
|
922
|
+
isList: false
|
|
923
|
+
}
|
|
924
|
+
]
|
|
925
|
+
}]);
|
|
926
|
+
let issues = DcbValidation$Reventless.validatePartitionHintsVsInference([
|
|
927
|
+
placeOrder,
|
|
928
|
+
newrecord,
|
|
929
|
+
assign
|
|
930
|
+
]);
|
|
931
|
+
globalThis.expect(issues.overrides.map(e => e.sliceName)).toEqual([]);
|
|
932
|
+
globalThis.expect(issues.contradictions.map(e => e.sliceName)).toEqual(["ShipOrder"]);
|
|
933
|
+
});
|
|
817
934
|
});
|
|
818
935
|
globalThis.describe("ambiguity surfacing", () => {
|
|
819
936
|
let aOwner = slice("A", undefined, undefined, [{
|