Comparator warnings should propagate to output of `==`
Warnings attached to the result of Comparator.compare do not propagate to the boolean return value of ==.
They don't propagate as they are removed
https://github.com/enso-org/enso/blame/c294e05fd7bb49f0393cd93b63aaee220b148c70/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsAtomNode.java#L108
and not attached back!
GitHub
Hybrid visual and textual functional programming. Contribute to enso-org/enso development by creating an account on GitHub.
This seems to fix the problem:
diff --git engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsAtomNode.java engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsAtomNode.java
index f335d9fc56..d5c211a373 100644
--- engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsAtomNode.java
+++ engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsAtomNode.java
@@ -14,7 +14,9 @@ import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.ConditionProfile;
+
import java.util.Arrays;
+
import org.enso.interpreter.node.callable.InvokeCallableNode.ArgumentsExecutionMode;
import org.enso.interpreter.node.callable.InvokeCallableNode.DefaultsExecutionMode;
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
@@ -28,6 +30,7 @@ import org.enso.interpreter.runtime.data.atom.AtomConstructor;
import org.enso.interpreter.runtime.data.atom.StructsLibrary;
import org.enso.interpreter.runtime.library.dispatch.TypeOfNode;
import org.enso.interpreter.runtime.state.State;
+import org.enso.interpreter.runtime.warning.AppendWarningNode;
import org.enso.interpreter.runtime.warning.WarningsLibrary;
@GenerateUncached
@@ -37,7 +40,7 @@ public abstract class EqualsAtomNode extends Node {
return EqualsAtomNodeGen.create();
}
- public abstract boolean execute(VirtualFrame frame, Atom left, Atom right);
+ public abstract Object execute(VirtualFrame frame, Atom left, Atom right);
static EqualsNode[] createEqualsNodes(int size) {
EqualsNode[] nodes = new EqualsNode[size];
@@ -71,8 +74,8 @@ public abstract class EqualsAtomNode extends Node {
for (int i = 0; i < fieldsLenCached; i++) {
var selfValue = structsLib.getField(self, i);
var otherValue = structsLib.getField(other, i);
- var fieldsAreEqual = fieldEqualsNodes[i].execute(frame, selfValue, otherValue);
- if (!fieldsAreEqual) {
+ var res = fieldEqualsNodes[i].execute(frame, selfValue, otherValue);
+ if (res instanceof Boolean fieldsAreEqual && !fieldsAreEqual) {
return false;
}
}
@@ -85,7 +88,8 @@ public abstract class EqualsAtomNode extends Node {
"cachedComparator != null",
},
limit = "10")
- boolean equalsAtomsWithCustomComparator(
+ Object equalsAtomsWithCustomComparator(
+ VirtualFrame frame,
Atom self,
Atom other,
@Cached("self.getConstructor()") AtomConstructor selfCtorCached,
@@ -94,6 +98,7 @@ public abstract class EqualsAtomNode extends Node {
@Cached(value = "findCompareMethod(cachedComparator)", allowUncached = true)
Function compareFn,
@Cached(value = "invokeCompareNode(compareFn)") InvokeFunctionNode invokeNode,
+ @Cached AppendWarningNode appendWarnings,
@Shared @CachedLibrary(limit = "10") WarningsLibrary warnings) {
try {
var otherComparator = customComparatorNode.execute(other);
@@ -105,9 +110,13 @@ public abstract class EqualsAtomNode extends Node {
var result = invokeNode.execute(compareFn, null, State.create(ctx), args);
assert orderingOrNullOrError(this, ctx, result, compareFn);
if (warnings.hasWarnings(result)) {
+ var map = warnings.getWarnings(result, false);
result = warnings.removeWarnings(result);
+ var equal = ctx.getBuiltins().ordering().newEqual() == result;
+ return appendWarnings.executeAppend(frame, equal, map);
+ } else {
+ return ctx.getBuiltins().ordering().newEqual() == result;
}
- return ctx.getBuiltins().ordering().newEqual() == result;
} catch (UnsupportedMessageException e) {
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
}
@@ -133,7 +142,7 @@ public abstract class EqualsAtomNode extends Node {
@Specialization(
replaces = {"equalsAtomsWithDefaultComparator", "equalsAtomsWithCustomComparator"})
- boolean equalsAtomsUncached(
+ Object equalsAtomsUncached(
VirtualFrame frame,
Atom self,
Atom other,
@@ -146,13 +155,14 @@ public abstract class EqualsAtomNode extends Node {
}
@CompilerDirectives.TruffleBoundary
- private boolean equalsAtomsUncached(
+ private Object equalsAtomsUncached(
MaterializedFrame frame, Atom self, Atom other, WarningsLibrary warnings) {
Type customComparator = CustomComparatorNode.getUncached().execute(self);
if (customComparator != null) {
Function compareFunc = findCompareMethod(customComparator);
var invokeFuncNode = invokeCompareNode(compareFunc);
return equalsAtomsWithCustomComparator(
+ frame,
self,
other,
self.getConstructor(),
@@ -160,13 +170,14 @@ public abstract class EqualsAtomNode extends Node {
customComparator,
compareFunc,
invokeFuncNode,
+ AppendWarningNode.getUncached(),
warnings);
}
for (int i = 0; i < self.getConstructor().getArity(); i++) {
var selfField = StructsLibrary.getUncached().getField(self, i);
var otherField = StructsLibrary.getUncached().getField(other, i);
- boolean areFieldsSame = EqualsNode.getUncached().execute(frame, selfField, otherField);
- if (!areFieldsSame) {
+ var res = EqualsNode.getUncached().execute(frame, selfField, otherField);
+ if (res instanceof Boolean areFieldsSame && !areFieldsSame) {
return false;
}
}
diff --git engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsComplexNode.java engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsComplexNode.java
index 6ce3da8006..4c03532568 100644
--- engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsComplexNode.java
+++ engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsComplexNode.java
@@ -1,5 +1,21 @@
package org.enso.interpreter.node.expression.builtin.meta;
+import java.time.LocalDateTime;
+import java.time.ZonedDateTime;
+
+import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
+import org.enso.interpreter.runtime.EnsoContext;
+import org.enso.interpreter.runtime.Module;
+import org.enso.interpreter.runtime.callable.UnresolvedConversion;
+import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
+import org.enso.interpreter.runtime.data.EnsoFile;
+import org.enso.interpreter.runtime.data.Type;
+import org.enso.interpreter.runtime.data.atom.Atom;
+import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
+import org.enso.interpreter.runtime.scope.ModuleScope;
+import org.enso.interpreter.runtime.warning.AppendWarningNode;
+import org.enso.interpreter.runtime.warning.WarningsLibrary;
+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Exclusive;
@@ -17,19 +33,6 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.Node;
-import java.time.LocalDateTime;
-import java.time.ZonedDateTime;
-import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
-import org.enso.interpreter.runtime.EnsoContext;
-import org.enso.interpreter.runtime.Module;
-import org.enso.interpreter.runtime.callable.UnresolvedConversion;
-import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
-import org.enso.interpreter.runtime.data.EnsoFile;
-import org.enso.interpreter.runtime.data.Type;
-import org.enso.interpreter.runtime.data.atom.Atom;
-import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
-import org.enso.interpreter.runtime.scope.ModuleScope;
-import org.enso.interpreter.runtime.warning.WarningsLibrary;
@GenerateUncached
public abstract class EqualsComplexNode extends Node {
@@ -38,21 +41,24 @@ public abstract class EqualsComplexNode extends Node {
return EqualsComplexNodeGen.create();
}
- public abstract boolean execute(VirtualFrame frame, Object left, Object right);
+ public abstract Object execute(VirtualFrame frame, Object left, Object right);
/** Enso specific types */
@Specialization
- boolean equalsUnresolvedSymbols(
+ Object equalsUnresolvedSymbols(
VirtualFrame frame,
UnresolvedSymbol self,
UnresolvedSymbol otherSymbol,
@Shared("equalsNode") @Cached EqualsNode equalsNode) {
- return self.getName().equals(otherSymbol.getName())
- && equalsNode.execute(frame, self.getScope(), otherSymbol.getScope());
+ if (!self.getName().equals(otherSymbol.getName())) {
+ return false;
+ } else {
+ return equalsNode.execute(frame, self.getScope(), otherSymbol.getScope());
+ }
}
@Specialization
- boolean equalsUnresolvedConversion(
+ Object equalsUnresolvedConversion(
VirtualFrame frame,
UnresolvedConversion selfConversion,
UnresolvedConversion otherConversion,
@@ -71,7 +77,7 @@ public abstract class EqualsComplexNode extends Node {
}
@Specialization
- boolean equalsFiles(
+ Object equalsFiles(
VirtualFrame frame,
EnsoFile selfFile,
EnsoFile otherFile,
@@ -85,7 +91,7 @@ public abstract class EqualsComplexNode extends Node {
* specialization disjunctive. So we rather specialize directly for {@link Type types}.
*/
@Specialization(guards = {"typesLib.hasType(selfType)", "typesLib.hasType(otherType)"})
- boolean equalsTypes(
+ Object equalsTypes(
VirtualFrame frame,
Type selfType,
Type otherType,
@@ -103,12 +109,13 @@ public abstract class EqualsComplexNode extends Node {
"selfWarnLib.hasWarnings(selfWithWarnings) || otherWarnLib.hasWarnings(otherWithWarnings)"
},
limit = "3")
- boolean equalsWithWarnings(
+ Object equalsWithWarnings(
VirtualFrame frame,
Object selfWithWarnings,
Object otherWithWarnings,
@CachedLibrary("selfWithWarnings") WarningsLibrary selfWarnLib,
@CachedLibrary("otherWithWarnings") WarningsLibrary otherWarnLib,
+ @Cached AppendWarningNode appendNode,
@Shared("equalsNode") @Cached EqualsNode equalsNode) {
try {
Object self =
@@ -119,7 +126,16 @@ public abstract class EqualsComplexNode extends Node {
otherWarnLib.hasWarnings(otherWithWarnings)
? otherWarnLib.removeWarnings(otherWithWarnings)
: otherWithWarnings;
- return equalsNode.execute(frame, self, other);
+ Object res = equalsNode.execute(frame, self, other);
+ if (selfWarnLib.hasWarnings(selfWithWarnings)) {
+ var w = selfWarnLib.getWarnings(selfWithWarnings, false);
+ res = appendNode.executeAppend(frame, res, w);
+ }
+ if (otherWarnLib.hasWarnings(otherWithWarnings)) {
+ var w = otherWarnLib.getWarnings(otherWithWarnings, false);
+ res = appendNode.executeAppend(frame, res, w);
+ }
+ return res;
} catch (UnsupportedMessageException e) {
throw EnsoContext.get(this).raiseAssertionPanic(this, null, e);
}
@@ -299,8 +315,8 @@ public abstract class EqualsComplexNode extends Node {
for (long i = 0; i < selfSize; i++) {
Object selfElem = valueToEnsoNode.execute(selfInterop.readArrayElement(selfArray, i));
Object otherElem = valueToEnsoNode.execute(otherInterop.readArrayElement(otherArray, i));
- boolean elemsAreEqual = equalsNode.execute(frame, selfElem, otherElem);
- if (!elemsAreEqual) {
+ var res = equalsNode.execute(frame, selfElem, otherElem);
+ if (res instanceof Boolean elemsAreEqual && !elemsAreEqual) {
return false;
}
}
@@ -344,7 +360,8 @@ public abstract class EqualsComplexNode extends Node {
&& otherInterop.isHashEntryReadable(otherHashMap, key)) {
Object otherValue =
valueToEnsoNode.execute(otherInterop.readHashValue(otherHashMap, key));
- if (!equalsNode.execute(frame, selfValue, otherValue)) {
+ var res = equalsNode.execute(frame, selfValue, otherValue);
+ if (res instanceof Boolean b && !b) {
return false;
}
} else {
@@ -397,7 +414,7 @@ public abstract class EqualsComplexNode extends Node {
// HostFunction is identified by a qualified name, it is not a lambda.
// It has well-defined equality based on the qualified name.
@Specialization(guards = {"isJavaFunction(selfHostFunc)", "isJavaFunction(otherHostFunc)"})
- boolean equalsHostFunctions(
+ Object equalsHostFunctions(
VirtualFrame frame,
Object selfHostFunc,
Object otherHostFunc,
diff --git engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java
index 4b130c4703..a6649387bc 100644
--- engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java
+++ engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsNode.java
@@ -84,9 +84,9 @@ public final class EqualsNode extends Node {
* @param other the other object
* @return {@code true} if {@code self} and {@code that} seem equal
*/
- public boolean execute(VirtualFrame frame, Object self, Object other) {
- var areEqual = node.execute(frame, self, other);
- if (!areEqual) {
+ public Object execute(VirtualFrame frame, Object self, Object other) {
+ var res = node.execute(frame, self, other);
+ if (res instanceof Boolean areEqual && !areEqual) {
var selfType = types.execute(self);
var otherType = types.execute(other);
if (selfType != otherType) {
@@ -97,7 +97,7 @@ public final class EqualsNode extends Node {
return convert.executeWithConversion(frame, other, self);
}
}
- return areEqual;
+ return res;
}
/**
@@ -116,7 +116,7 @@ public final class EqualsNode extends Node {
* @return {code false} if the conversion makes no sense or result of equality check after doing
* the conversion
*/
- abstract boolean executeWithConversion(VirtualFrame frame, Object self, Object that);
+ abstract Object executeWithConversion(VirtualFrame frame, Object self, Object that);
static Type findType(TypeOfNode typeOfNode, Object obj) {
var rawType = typeOfNode.execute(obj);
@@ -202,7 +202,7 @@ public final class EqualsNode extends Node {
"selfType == findType(typeOfNode, self)",
"thatType == findType(typeOfNode, that)"
})
- final boolean doConversionCached(
+ final Object doConversionCached(
VirtualFrame frame,
Object self,
Object that,
@@ -225,7 +225,7 @@ public final class EqualsNode extends Node {
}
@Specialization(replaces = "doConversionCached")
- final boolean doConversionUncached(
+ final Object doConversionUncached(
VirtualFrame frame,
Object self,
Object that,
@@ -245,7 +245,7 @@ public final class EqualsNode extends Node {
return false;
}
- private boolean doDispatch(
+ private Object doDispatch(
VirtualFrame frame,
Object self,
Object that,
@@ -260,7 +260,9 @@ public final class EqualsNode extends Node {
try {
var thatAsSelf = convertNode.execute(convert, state, new Object[] {selfType, that});
var result = equalityNode.execute(frame, self, thatAsSelf);
- assert !result || assertHashCodeIsTheSame(that, thatAsSelf);
+ if (result instanceof Boolean b) {
+ assert !b || assertHashCodeIsTheSame(that, thatAsSelf);
+ }
return result;
} catch (ArityException ex) {
var assertsOn = false;
diff --git engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsSimpleNode.java engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsSimpleNode.java
index 459fc90fa3..efa1aa5b09 100644
--- engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsSimpleNode.java
+++ engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/meta/EqualsSimpleNode.java
@@ -33,7 +33,7 @@ public abstract class EqualsSimpleNode extends Node {
return EqualsSimpleNodeGen.create();
}
- public abstract boolean execute(VirtualFrame frame, Object self, Object right);
+ public abstract Object execute(VirtualFrame frame, Object self, Object right);
@Specialization
boolean equalsBoolBool(boolean self, boolean other) {
@@ -296,17 +296,21 @@ public abstract class EqualsSimpleNode extends Node {
}
@Specialization
- boolean equalsAtoms(
+ Object equalsAtoms(
VirtualFrame frame,
Atom self,
Atom other,
@Cached EqualsAtomNode equalsAtomNode,
@Shared("isSameObjectNode") @Cached IsSameObjectNode isSameObjectNode) {
- return isSameObjectNode.execute(self, other) || equalsAtomNode.execute(frame, self, other);
+ if (isSameObjectNode.execute(self, other)) {
+ return true;
+ } else {
+ return equalsAtomNode.execute(frame, self, other);
+ }
}
@Specialization
- boolean equalsReverseLong(
+ Object equalsReverseLong(
VirtualFrame frame,
TruffleObject self,
long other,
@@ -316,7 +320,7 @@ public abstract class EqualsSimpleNode extends Node {
}
@Specialization
- boolean equalsReverseDouble(
+ Object equalsReverseDouble(
VirtualFrame frame,
TruffleObject self,
double other,
@@ -326,7 +330,7 @@ public abstract class EqualsSimpleNode extends Node {
}
@Specialization
- boolean equalsReverseBigInt(
+ Object equalsReverseBigInt(
VirtualFrame frame,
TruffleObject self,
EnsoBigInteger other,
@@ -336,7 +340,7 @@ public abstract class EqualsSimpleNode extends Node {
}
@Specialization(guards = "isNotPrimitive(self, other, interop, warnings)")
- boolean equalsComplex(
+ Object equalsComplex(
VirtualFrame frame,
Object self,
Object other,
@@ -344,7 +348,11 @@ public abstract class EqualsSimpleNode extends Node {
@Shared("isSameObjectNode") @Cached IsSameObjectNode isSameObjectNode,
@Shared("interop") @CachedLibrary(limit = "10") InteropLibrary interop,
@CachedLibrary(limit = "5") WarningsLibrary warnings) {
- return isSameObjectNode.execute(self, other) || equalsComplex.execute(frame, self, other);
+ if (isSameObjectNode.execute(self, other)) {
+ return true;
+ } else {
+ return equalsComplex.execute(frame, self, other);
+ }
}
static boolean isNotPrimitive(
diff --git engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java
index 65f7bd860a..1237a86701 100644
--- engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java
+++ engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java
@@ -612,7 +612,7 @@ public abstract class SortVectorNode extends Node {
}
int compareValuesWithDefaultComparator(Object x, Object y) {
- if (equalsNode.execute(frame, x, y)) {
+ if (equalsNode.execute(frame, x, y) instanceof Boolean b && b) {
return 0;
} else {
// Check if x < y
diff --git engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/EnsoHashMapBuilder.java engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/EnsoHashMapBuilder.java
index 5a69d250d6..97ca877b48 100644
--- engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/EnsoHashMapBuilder.java
+++ engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/EnsoHashMapBuilder.java
@@ -298,7 +298,7 @@ final class EnsoHashMapBuilder {
if (a instanceof Double aDbl && b instanceof Double bDbl && aDbl.isNaN() && bDbl.isNaN()) {
return true;
} else {
- return equalsNode.execute(frame, a, b);
+ return equalsNode.execute(frame, a, b) instanceof Boolean r && r;
}
}
diff --git engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapRemoveNode.java engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapRemoveNode.java
index ea94d41d2f..61f754abd6 100644
--- engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapRemoveNode.java
+++ engine/runtime/src/main/java/org/enso/interpreter/runtime/data/hash/HashMapRemoveNode.java
@@ -102,7 +102,7 @@ public abstract class HashMapRemoveNode extends Node {
if (isNan(obj1, interop) && isNan(obj2, interop)) {
return true;
} else {
- return equalsNode.execute(frame, obj1, obj2);
+ return equalsNode.execute(frame, obj1, obj2) instanceof Boolean b && b;
}
}
diff --git test/Base_Internal_Tests/src/Comparator_Spec.enso test/Base_Internal_Tests/src/Comparator_Spec.enso
index 036658ba5c..3e8aef3bc0 100644
--- test/Base_Internal_Tests/src/Comparator_Spec.enso
+++ test/Base_Internal_Tests/src/Comparator_Spec.enso
@@ -98,6 +98,16 @@ add_specs suite_builder = suite_builder.group "Object Comparator" group_builder-
((Attach_Warning.Value 1) == (Attach_Warning.Value 1)) . should_be_true
((Attach_Warning.Value 1) == (Attach_Warning.Value2 1)) . should_be_true
+ group_builder.specify "warnings attached in a comparator should propagate to the operator result" <|
+ Problems.expect_only_warning Illegal_Argument <| ((Attach_Warning.Value 1) < (Attach_Warning.Value 2))
+ Problems.expect_only_warning Illegal_Argument <| ((Attach_Warning.Value 1) >= (Attach_Warning.Value 2))
+ # TODO: https://github.com/enso-org/enso/issues/10679
+ Problems.expect_only_warning Illegal_Argument <|
+ v1 = Attach_Warning.Value 1
+ v2 = Attach_Warning.Value 2
+ r = v1 == v2
+ r
+
main filter=Nothing =
suite = Test.build suite_builder->
add_specs suite_builder
I am not really happy about the need to change return type of EqualsNode.execute to Object. I'll think about a solution that doesn't need such a change.
Jaroslav Tulach reports a new STANDUP for yesterday (2024-09-25):
Progress: .
- integrated https://github.com/enso-org/enso/pull/11009
- using IGV to find optimization for
==: https://github.com/enso-org/enso/pull/11009/commits/2c4b5225226a3fa0eae36367fec528e6b928d849 - found
/vs.\problem: https://github.com/enso-org/enso/pull/10823/commits/10dc148f66434f6d10dcbf8d821771a072055cd2 - fixed "catch panic": https://github.com/enso-org/enso/issues/9402#issuecomment-2373351452
- duplicated https://github.com/enso-org/enso/issues/9063
- another update of GraalVM PR: https://github.com/oracle/graal/pull/8266#issuecomment-2373992990
- #9402 fixed by PR https://github.com/enso-org/enso/pull/11167
- meetings and standups It should be finished by 2024-09-25.