@@ -230,6 +230,104 @@ gremlin> g.inject([Float.MAX_VALUE, Float.MAX_VALUE], [Double.MAX_VALUE, Double.
230230
231231See link:https://issues.apache.org/jira/browse/TINKERPOP-3115[TINKERPOP-3115]
232232
233+ ==== repeat() Step Global Children Semantics Change
234+
235+ The `repeat()` step has been updated to treat the repeat traversal as a global child in all cases. Previously, the
236+ repeat traversal behaved as a hybrid between local and global semantics, which could lead to unexpected results in
237+ certain scenarios. The repeat traversal started off as a local child but as traversers were added back per iteration,
238+ it behaved more like a global child.
239+
240+ With this change, the repeat traversal now consistently operates with global semantics, meaning that all traversers
241+ are processed together rather than being processed per traverser. This provides more predictable behavior and aligns
242+ with the semantics of other steps.
243+
244+ [source,text]
245+ ----
246+ // In 3.7.x and earlier, the order would be local to the first traverser.
247+ // Notice how the results are grouped by marko, then vadas, then lop
248+ gremlin> g.withoutStrategies(RepeatUnrollStrategy).V(1, 2, 3).
249+ ......1> repeat(both().simplePath().order().by("name")).times(2).path().by("name")
250+ ==>[marko,lop,josh]
251+ ==>[marko,josh,lop]
252+ ==>[marko,lop,peter]
253+ ==>[marko,josh,ripple]
254+ ==>[vadas,marko,josh]
255+ ==>[vadas,marko,lop]
256+ ==>[lop,marko,josh]
257+ ==>[lop,josh,marko]
258+ ==>[lop,josh,ripple]
259+ ==>[lop,marko,vadas]
260+
261+ // In 3.8.0, the repeat now consistently uses global semantics
262+ // The traversers from the final iteration are ordered first then by the traversers from previous iterations
263+ gremlin> g.withoutStrategies(RepeatUnrollStrategy).V(1, 2, 3).
264+ ......1> repeat(both().simplePath().order().by("name")).times(2).path().by("name")
265+ ==>[marko,lop,josh]
266+ ==>[vadas,marko,josh]
267+ ==>[lop,marko,josh]
268+ ==>[marko,josh,lop]
269+ ==>[vadas,marko,lop]
270+ ==>[lop,josh,marko]
271+ ==>[marko,lop,peter]
272+ ==>[marko,josh,ripple]
273+ ==>[lop,josh,ripple]
274+ ==>[lop,marko,vadas]
275+ ----
276+
277+ This change may affect traversals that relied on the previous hybrid behavior, particularly those using side effects
278+ or barrier steps within `repeat()`. Review any traversals using `repeat()` with steps like `aggregate()`, `store()`,
279+ or other barrier steps to ensure they produce the expected results.
280+
281+ If you would like `repeat()` to behave similarly to how it did in 3.7.x, then you should wrap the repeat inside a
282+ `local()`. The following example demonstrates this:
283+
284+ [source,text]
285+ ----
286+ // In 3.7.x
287+ gremlin> g.V().repeat(both().simplePath().order().by("name")).times(2).path().by("name")
288+ ==>[marko,lop,josh]
289+ ==>[marko,josh,lop]
290+ ==>[marko,lop,peter]
291+ ==>[marko,josh,ripple]
292+ ==>[vadas,marko,josh]
293+ ==>[vadas,marko,lop]
294+ ==>[lop,marko,josh]
295+ ==>[lop,josh,marko]
296+ ==>[lop,josh,ripple]
297+ ==>[lop,marko,vadas]
298+ ==>[josh,marko,lop]
299+ ==>[josh,lop,marko]
300+ ==>[josh,lop,peter]
301+ ==>[josh,marko,vadas]
302+ ==>[ripple,josh,lop]
303+ ==>[ripple,josh,marko]
304+ ==>[peter,lop,josh]
305+ ==>[peter,lop,marko]
306+
307+ // In 3.8.0, placing the repeat inside a local will again cause the repeat traversal to apply per traverser (locally)
308+ gremlin> g.V().local(repeat(both().simplePath().order().by("name")).times(2)).path().by("name")
309+ ==>[marko,lop,josh]
310+ ==>[marko,josh,lop]
311+ ==>[marko,lop,peter]
312+ ==>[marko,josh,ripple]
313+ ==>[vadas,marko,josh]
314+ ==>[vadas,marko,lop]
315+ ==>[lop,marko,josh]
316+ ==>[lop,josh,marko]
317+ ==>[lop,josh,ripple]
318+ ==>[lop,marko,vadas]
319+ ==>[josh,marko,lop]
320+ ==>[josh,lop,marko]
321+ ==>[josh,lop,peter]
322+ ==>[josh,marko,vadas]
323+ ==>[ripple,josh,lop]
324+ ==>[ripple,josh,marko]
325+ ==>[peter,lop,josh]
326+ ==>[peter,lop,marko]
327+ ----
328+
329+ See: link:https://issues.apache.org/jira/browse/TINKERPOP-3200[TINKERPOP-3200]
330+
233331==== Prefer OffsetDateTime
234332
235333The default implementation for date type in Gremlin is now changed from the `java.util.Date` to the more encompassing
@@ -1128,6 +1226,62 @@ The `ChooseStep` now provides a `ChooseSemantics` enum which helps indicate if t
11281226
11291227See: link:https://issues.apache.org/jira/browse/TINKERPOP-3178[TINKERPOP-3178]
11301228
1229+ ===== repeat() Step Global Children Semantics Change
1230+
1231+ The `RepeatStep` has been updated to consistently treat the repeat traversal as a global child rather than using
1232+ hybrid local/global semantics. This change affects how the repeat traversal processes traversers and interacts with
1233+ the parent traversal.
1234+
1235+ Previously, `RepeatStep` would start with local semantics for the first iteration and then switch to global semantics
1236+ for the subsequent iterations, which created inconsistencies in how side effects and barriers behaved within the repeat
1237+ traversal. The biggest change will be to `Barrier` steps in the repeat traversal as they will now have access to all
1238+ the starting traversers.
1239+
1240+ [source,text]
1241+ ----
1242+ // In 3.7.x and earlier, the order would be local to the first traverser.
1243+ // Notice how the results are grouped by marko, then vadas, then lop
1244+ gremlin> g.withoutStrategies(RepeatUnrollStrategy).V(1, 2, 3).
1245+ ......1> repeat(both().simplePath().order().by("name")).times(2).path().by("name")
1246+ ==>[marko,lop,josh]
1247+ ==>[marko,josh,lop]
1248+ ==>[marko,lop,peter]
1249+ ==>[marko,josh,ripple]
1250+ ==>[vadas,marko,josh]
1251+ ==>[vadas,marko,lop]
1252+ ==>[lop,marko,josh]
1253+ ==>[lop,josh,marko]
1254+ ==>[lop,josh,ripple]
1255+ ==>[lop,marko,vadas]
1256+
1257+ // In 3.8.0, the aggregate now consistently uses global semantics
1258+ // The traversers are now ordered so the traversers from the final iteration are ordered first then by
1259+ // the traversers from previous iterations
1260+ gremlin> g.withoutStrategies(RepeatUnrollStrategy).V(1, 2, 3).
1261+ ......1> repeat(both().simplePath().order().by("name")).times(2).path().by("name")
1262+ ==>[marko,lop,josh]
1263+ ==>[vadas,marko,josh]
1264+ ==>[lop,marko,josh]
1265+ ==>[marko,josh,lop]
1266+ ==>[vadas,marko,lop]
1267+ ==>[lop,josh,marko]
1268+ ==>[marko,lop,peter]
1269+ ==>[marko,josh,ripple]
1270+ ==>[lop,josh,ripple]
1271+ ==>[lop,marko,vadas]
1272+ ----
1273+
1274+ Providers implementing custom optimizations or strategies around `RepeatStep` should verify that their
1275+ implementations account for the repeat traversal being a global child. This particularly affects:
1276+
1277+ - Strategies that analyze or transform repeat traversals
1278+ - Optimizations that depend on the scope semantics of child traversals
1279+
1280+ The last point about optimizations may be particularly important for providers that have memory constraints as this
1281+ change may bring about higher memory usage due to more traversers needing to be held in memory.
1282+
1283+ See: link:https://issues.apache.org/jira/browse/TINKERPOP-3200[TINKERPOP-3200]
1284+
11311285===== Prefer OffsetDateTime
11321286
11331287The default implementation for date type in Gremlin is now changed from the deprecated `java.util.Date` to the more
0 commit comments