////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
////
== TinkerPop 3.8.1

*Release Date: April 1, 2026*

Please see the link:https://github.com/apache/tinkerpop/blob/3.8.1/CHANGELOG.asciidoc#release-3-8-1[changelog] for a
complete list of all the modifications that are part of this release.

=== Upgrading for Users

==== Gremlint MCP

The Gremlin MCP server now exposes Gremlint formatting for Gremlin traversals, which can be a convenient way to make
a long string of Gremlin easier to read directly from an AI assistant. Provide a simple prompt like the following to
an AI coding agent:

[source,text]
----
Format this Gremlin query:
```
g.V().union(limit(3).fold(),tail(3).fold()).local(
  unfold().order().by(bothE().count(),desc).limit(1).fold())
```
----

It will trigger a call to Gremlint within the Gremlin MCP Server to format it with better indentation and spacing.

==== Gremlint Improvements

Gremlint's approach to newlines often produced formatting that didn't generally follow the espoused best practices.
Specifically, if Gremlint found that arguments to a step would exceed the line length, it would instantly apply a
newline and then do an indent. This formatting rule made certain Gremlin appear stretched out vertically in many cases.

The following example demonstrates this stretching. The following bit of Gremlin is manually formatted according to
common norms and best practices:

[source,groovy]
----
g.V().as("v").
  repeat(both().simplePath().as("v")).emit().
  filter(project("x","y","z").by(select(first, "v")).
                              by(select(last, "v")).
                              by(select(all, "v").count(local)).as("triple").
         coalesce(select("x","y").as("a").
                    select("triples").unfold().as("t").
                    select("x","y").where(eq("a")).
                    select("t"),
                  local(aggregate("triples"))).
         select("z").as("length").
         select("triple").select("z").where(eq("length"))).
  select(all, "v").unfold().
  groupCount()
----

In earlier versions of Gremlint, it would format that query to:

[source,groovy]
----
g.V().as("v").
  repeat(both().simplePath().as("v")).emit().
  filter(
    project("x", "y", "z").
      by(select(first, "v")).
      by(select(last, "v")).
      by(select(all, "v").count(local)).
      as("triple").
    coalesce(
      select("x", "y").as("a").
      select("triples").
      unfold().as("t").
      select("x", "y").
      where(eq("a")).
      select("t"),
      local(aggregate("triples"))).
    select("z").as("length").
    select("triple").
    select("z").
    where(eq("length"))).
  select(all, "v").
  unfold().
  groupCount()
----

In this version, after the improvements mentioned above, Gremlint now produces:

[source,groovy]
----
g.V().as("v").
  repeat(both().simplePath().as("v")).emit().
  filter(project("x", "y", "z").
           by(select(first, "v")).
           by(select(last, "v")).
           by(select(all, "v").count(local)).
           as("triple").
         coalesce(select("x", "y").as("a").
                  select("triples").
                  unfold().as("t").
                  select("x", "y").
                  where(eq("a")).
                  select("t"), local(aggregate("triples"))).
         select("z").as("length").
         select("triple").
         select("z").
         where(eq("length"))).
  select(all, "v").
  unfold().
  groupCount()
----

This more compact representation presents a form much more in line with the manually formatted one. While there is still
room to improve, Gremlint now produces a format that is more likely to be usable without additional manual formatting
intervention.

=== Upgrading for Providers

==== Graph System Providers

===== New Gherkin Test Tags

New Gherkin test tags have been added for scenarios that require the graph to support specific property value types:
`@AllowDateTimePropertyValues`, `@AllowListPropertyValues`, `@AllowMapPropertyValues`, `@AllowSetPropertyValues`, and
`@AllowUUIDPropertyValues`. Providers whose graphs do not support storing these types as property values should exclude
the relevant tags in their `@CucumberOptions`. The full list of tags can be found
link:https://tinkerpop.apache.org/docs/3.8.1/dev/developer/#gherkin-tags[here].

