@@ -262,6 +262,104 @@ gremlin> g.inject([Float.MAX_VALUE, Float.MAX_VALUE], [Double.MAX_VALUE, Double.
262262
263263See link:https://issues.apache.org/jira/browse/TINKERPOP-3115[TINKERPOP-3115]
264264
265+ ==== repeat() Step Global Children Semantics Change
266+
267+ The `repeat()` step has been updated to treat the repeat traversal as a global child in all cases. Previously, the
268+ repeat traversal behaved as a hybrid between local and global semantics, which could lead to unexpected results in
269+ certain scenarios. The repeat traversal started off as a local child but as traversers were added back per iteration,
270+ it behaved more like a global child.
271+
272+ With this change, the repeat traversal now consistently operates with global semantics, meaning that all traversers
273+ are processed together rather than being processed per traverser. This provides more predictable behavior and aligns
274+ with the semantics of other steps.
275+
276+ [source,text]
277+ ----
278+ // In 3.7.x and earlier, the order would be local to the first traverser.
279+ // Notice how the results are grouped by marko, then vadas, then lop
280+ gremlin> g.withoutStrategies(RepeatUnrollStrategy).V(1, 2, 3).
281+ ......1> repeat(both().simplePath().order().by("name")).times(2).path().by("name")
282+ ==>[marko,lop,josh]
283+ ==>[marko,josh,lop]
284+ ==>[marko,lop,peter]
285+ ==>[marko,josh,ripple]
286+ ==>[vadas,marko,josh]
287+ ==>[vadas,marko,lop]
288+ ==>[lop,marko,josh]
289+ ==>[lop,josh,marko]
290+ ==>[lop,josh,ripple]
291+ ==>[lop,marko,vadas]
292+
293+ // In 3.8.0, the repeat now consistently uses global semantics
294+ // The traversers from the final iteration are ordered first then by the traversers from previous iterations
295+ gremlin> g.withoutStrategies(RepeatUnrollStrategy).V(1, 2, 3).
296+ ......1> repeat(both().simplePath().order().by("name")).times(2).path().by("name")
297+ ==>[marko,lop,josh]
298+ ==>[vadas,marko,josh]
299+ ==>[lop,marko,josh]
300+ ==>[marko,josh,lop]
301+ ==>[vadas,marko,lop]
302+ ==>[lop,josh,marko]
303+ ==>[marko,lop,peter]
304+ ==>[marko,josh,ripple]
305+ ==>[lop,josh,ripple]
306+ ==>[lop,marko,vadas]
307+ ----
308+
309+ This change may affect traversals that relied on the previous hybrid behavior, particularly those using side effects
310+ or barrier steps within `repeat()`. Review any traversals using `repeat()` with steps like `aggregate()`, `store()`,
311+ or other barrier steps to ensure they produce the expected results.
312+
313+ If you would like `repeat()` to behave similarly to how it did in 3.7.x, then you should wrap the repeat inside a
314+ `local()`. The following example demonstrates this:
315+
316+ [source,text]
317+ ----
318+ // In 3.7.x
319+ gremlin> g.V().repeat(both().simplePath().order().by("name")).times(2).path().by("name")
320+ ==>[marko,lop,josh]
321+ ==>[marko,josh,lop]
322+ ==>[marko,lop,peter]
323+ ==>[marko,josh,ripple]
324+ ==>[vadas,marko,josh]
325+ ==>[vadas,marko,lop]
326+ ==>[lop,marko,josh]
327+ ==>[lop,josh,marko]
328+ ==>[lop,josh,ripple]
329+ ==>[lop,marko,vadas]
330+ ==>[josh,marko,lop]
331+ ==>[josh,lop,marko]
332+ ==>[josh,lop,peter]
333+ ==>[josh,marko,vadas]
334+ ==>[ripple,josh,lop]
335+ ==>[ripple,josh,marko]
336+ ==>[peter,lop,josh]
337+ ==>[peter,lop,marko]
338+
339+ // In 3.8.0, placing the repeat inside a local will again cause the repeat traversal to apply per traverser (locally)
340+ gremlin> g.V().local(repeat(both().simplePath().order().by("name")).times(2)).path().by("name")
341+ ==>[marko,lop,josh]
342+ ==>[marko,josh,lop]
343+ ==>[marko,lop,peter]
344+ ==>[marko,josh,ripple]
345+ ==>[vadas,marko,josh]
346+ ==>[vadas,marko,lop]
347+ ==>[lop,marko,josh]
348+ ==>[lop,josh,marko]
349+ ==>[lop,josh,ripple]
350+ ==>[lop,marko,vadas]
351+ ==>[josh,marko,lop]
352+ ==>[josh,lop,marko]
353+ ==>[josh,lop,peter]
354+ ==>[josh,marko,vadas]
355+ ==>[ripple,josh,lop]
356+ ==>[ripple,josh,marko]
357+ ==>[peter,lop,josh]
358+ ==>[peter,lop,marko]
359+ ----
360+
361+ See: link:https://issues.apache.org/jira/browse/TINKERPOP-3200[TINKERPOP-3200]
362+
265363==== Prefer OffsetDateTime
266364
267365The default implementation for date type in Gremlin is now changed from the `java.util.Date` to the more encompassing
@@ -957,35 +1055,6 @@ gremlin> g.withoutStrategies(RepeatUnrollStrategy).V().values('name').repeat(inj
9571055==>peter
9581056----
9591057
960- Another example is the usage of `aggregate()` inside `repeat()`. The following results returned from the `modern` graph
961- demonstrate the change of semantics if the `aggregate()` in `repeat()` were to be unrolled:
962-
963- [source,text]
964- ----
965- gremlin> g.V().both().aggregate('x').both().aggregate('x').limit(10)
966- ==>v[1]
967- ==>v[1]
968- ==>v[1]
969- ==>v[1]
970- ==>v[1]
971- ==>v[1]
972- ==>v[1]
973- ==>v[4]
974- ==>v[4]
975- ==>v[4]
976- gremlin> g.withoutStrategies(RepeatUnrollStrategy).V().repeat(both().aggregate('x')).times(2).limit(10)
977- ==>v[1]
978- ==>v[1]
979- ==>v[1]
980- ==>v[4]
981- ==>v[6]
982- ==>v[5]
983- ==>v[3]
984- ==>v[3]
985- ==>v[2]
986- ==>v[4]
987- ----
988-
9891058Other examples of affected traversals include (but are not limited to):
9901059
9911060[source,groovy]
@@ -1168,6 +1237,62 @@ The `ChooseStep` now provides a `ChooseSemantics` enum which helps indicate if t
11681237
11691238See: link:https://issues.apache.org/jira/browse/TINKERPOP-3178[TINKERPOP-3178]
11701239
1240+ ===== repeat() Step Global Children Semantics Change
1241+
1242+ The `RepeatStep` has been updated to consistently treat the repeat traversal as a global child rather than using
1243+ hybrid local/global semantics. This change affects how the repeat traversal processes traversers and interacts with
1244+ the parent traversal.
1245+
1246+ Previously, `RepeatStep` would start with local semantics for the first iteration and then switch to global semantics
1247+ for the subsequent iterations, which created inconsistencies in how side effects and barriers behaved within the repeat
1248+ traversal. The biggest change will be to `Barrier` steps in the repeat traversal as they will now have access to all
1249+ the starting traversers.
1250+
1251+ [source,text]
1252+ ----
1253+ // In 3.7.x and earlier, the order would be local to the first traverser.
1254+ // Notice how the results are grouped by marko, then vadas, then lop
1255+ gremlin> g.withoutStrategies(RepeatUnrollStrategy).V(1, 2, 3).
1256+ ......1> repeat(both().simplePath().order().by("name")).times(2).path().by("name")
1257+ ==>[marko,lop,josh]
1258+ ==>[marko,josh,lop]
1259+ ==>[marko,lop,peter]
1260+ ==>[marko,josh,ripple]
1261+ ==>[vadas,marko,josh]
1262+ ==>[vadas,marko,lop]
1263+ ==>[lop,marko,josh]
1264+ ==>[lop,josh,marko]
1265+ ==>[lop,josh,ripple]
1266+ ==>[lop,marko,vadas]
1267+
1268+ // In 3.8.0, the aggregate now consistently uses global semantics
1269+ // The traversers are now ordered so the traversers from the final iteration are ordered first then by
1270+ // the traversers from previous iterations
1271+ gremlin> g.withoutStrategies(RepeatUnrollStrategy).V(1, 2, 3).
1272+ ......1> repeat(both().simplePath().order().by("name")).times(2).path().by("name")
1273+ ==>[marko,lop,josh]
1274+ ==>[vadas,marko,josh]
1275+ ==>[lop,marko,josh]
1276+ ==>[marko,josh,lop]
1277+ ==>[vadas,marko,lop]
1278+ ==>[lop,josh,marko]
1279+ ==>[marko,lop,peter]
1280+ ==>[marko,josh,ripple]
1281+ ==>[lop,josh,ripple]
1282+ ==>[lop,marko,vadas]
1283+ ----
1284+
1285+ Providers implementing custom optimizations or strategies around `RepeatStep` should verify that their
1286+ implementations account for the repeat traversal being a global child. This particularly affects:
1287+
1288+ - Strategies that analyze or transform repeat traversals
1289+ - Optimizations that depend on the scope semantics of child traversals
1290+
1291+ The last point about optimizations may be particularly important for providers that have memory constraints as this
1292+ change may bring about higher memory usage due to more traversers needing to be held in memory.
1293+
1294+ See: link:https://issues.apache.org/jira/browse/TINKERPOP-3200[TINKERPOP-3200]
1295+
11711296===== Prefer OffsetDateTime
11721297
11731298The default implementation for date type in Gremlin is now changed from the deprecated `java.util.Date` to the more
0 commit comments