You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2026/07/29 19:15:21 UTC
(tinkerpop) branch master updated (b7a1affcec -> e5e2c9384f)
This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
from b7a1affcec Merge branch '3.8-dev'
add 314e5253dc Publish an agent-friendly Markdown docs mirror + llms.txt (agentdocsspec.com)
add 66662db9dc Add curated llms-summary descriptions to page-leading doc sections
add 54471af798 Split the traversal step catalog into one Markdown page per step
add ef7ead72c1 Keep each GraphSON version whole; split provider step semantics per step
add e3da9ebfa0 Make Markdown splitting purely summary-driven with a size lint
add c3b1ce9891 Fix llms.txt index entries for book landing pages and tutorials
add 1cedbe2a9a Fixed overflows in docs markdown publishing
add c2d5262add Document agent-friendly docs support and the tinkeradoc build step
add bbedd343ba Reference spun-off child pages from their parent in split Markdown
add ab9c5be0e7 Fixed llm-summary for gremlin-variants.asciidoc
add 1ea01331cc Fix mis-pasted Gremlin-Groovy and Gremlin.Net llms-summary text
add 48675b8374 Point the per-page llms.txt directive at this version's index
add cf6647db43 Fix truncated and malformed llms-summary text
add b716f14327 Stop tutorials rendering as two Markdown pages
new b75c29d797 Merge branch 'afd' into 3.7-dev
new ceb0404b88 Merge branch '3.7-dev' into 3.8-dev
new e5e2c9384f Merge branch '3.8-dev'
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
bin/process-docs.sh | 64 ++-
bin/publish-docs.sh | 32 ++
bin/validate-llms-txt.sh | 177 +++++++
docs/src/dev/developer/contributing.asciidoc | 4 +
.../dev/developer/development-environment.asciidoc | 70 ++-
docs/src/dev/developer/for-committers.asciidoc | 2 +
docs/src/dev/developer/index.asciidoc | 1 +
docs/src/dev/developer/release.asciidoc | 1 +
docs/src/dev/future/index.asciidoc | 1 +
docs/src/dev/io/index.asciidoc | 1 +
docs/src/dev/provider/gremlin-semantics.asciidoc | 36 ++
docs/src/dev/provider/index.asciidoc | 6 +
.../src/docinfo-footer.html | 19 +-
docs/src/recipes/between-vertices.asciidoc | 1 +
docs/src/recipes/centrality.asciidoc | 1 +
docs/src/recipes/collections.asciidoc | 1 +
docs/src/recipes/connected-components.asciidoc | 1 +
docs/src/recipes/cycle-detection.asciidoc | 1 +
docs/src/recipes/duplicate-edge.asciidoc | 1 +
docs/src/recipes/duplicate-vertex.asciidoc | 1 +
docs/src/recipes/edge-move.asciidoc | 1 +
docs/src/recipes/element-existence.asciidoc | 1 +
docs/src/recipes/if-then-based-grouping.asciidoc | 1 +
docs/src/recipes/index.asciidoc | 3 +
docs/src/recipes/looping.asciidoc | 1 +
docs/src/recipes/olap-spark-yarn.asciidoc | 1 +
.../recipes/operating-on-dropped-elements.asciidoc | 1 +
docs/src/recipes/pagination.asciidoc | 1 +
docs/src/recipes/recommendation.asciidoc | 1 +
docs/src/recipes/shortest-path.asciidoc | 1 +
docs/src/recipes/traversal-induced-values.asciidoc | 1 +
docs/src/recipes/tree.asciidoc | 1 +
docs/src/reference/gremlin-applications.asciidoc | 6 +
docs/src/reference/gremlin-variants.asciidoc | 7 +
.../implementations-hadoop-start.asciidoc | 1 +
docs/src/reference/implementations-intro.asciidoc | 1 +
docs/src/reference/intro.asciidoc | 1 +
docs/src/reference/preface.asciidoc | 1 +
docs/src/reference/the-graph.asciidoc | 1 +
docs/src/reference/the-graphcomputer.asciidoc | 1 +
docs/src/reference/the-traversal.asciidoc | 130 +++++
docs/src/tutorials/getting-started/index.asciidoc | 1 +
.../gremlin-language-variants/index.asciidoc | 3 +
docs/src/tutorials/gremlins-anatomy/index.asciidoc | 1 +
.../tutorials/the-gremlin-console/index.asciidoc | 1 +
docs/src/upgrade/index.asciidoc | 1 +
docs/src/upgrade/release-3.0.x-incubating.asciidoc | 1 +
docs/src/upgrade/release-3.1.x-incubating.asciidoc | 1 +
docs/src/upgrade/release-3.2.x-incubating.asciidoc | 3 +
docs/src/upgrade/release-3.3.x.asciidoc | 2 +
docs/src/upgrade/release-3.4.x.asciidoc | 2 +
docs/src/upgrade/release-3.5.x.asciidoc | 3 +
docs/src/upgrade/release-3.6.x.asciidoc | 1 +
docs/src/upgrade/release-3.7.x.asciidoc | 2 +
docs/tinkeradoc-extension/README.md | 14 +
...sion.java => GremlinDocsConverterRegistry.java} | 15 +-
.../tinkeradoc/GremlinExecutionCache.java | 94 ++++
.../tinkerpop/tinkeradoc/GremlinHighlighter.java | 117 +++++
.../tinkerpop/tinkeradoc/GremlinPostprocessor.java | 37 +-
.../tinkerpop/tinkeradoc/GremlinTreeprocessor.java | 213 +++++----
.../tinkerpop/tinkeradoc/HtmlTabRenderer.java | 67 +++
.../tinkerpop/tinkeradoc/LlmsTxtGenerator.java | 288 ++++++++++++
.../tinkerpop/tinkeradoc/MarkdownConverter.java | 501 ++++++++++++++++++++
.../tinkerpop/tinkeradoc/MarkdownSplitter.java | 521 +++++++++++++++++++++
.../tinkerpop/tinkeradoc/MarkdownTabRenderer.java | 103 ++++
.../apache/tinkerpop/tinkeradoc/NeutralTab.java | 84 ++++
.../tinkerpop/tinkeradoc/NeutralTabCodec.java | 221 +++++++++
...ciidoctor.jruby.converter.spi.ConverterRegistry | 1 +
.../tinkeradoc/DualBackendIntegrationTest.java | 118 +++++
.../tinkeradoc/GremlinExecutionCacheTest.java | 124 +++++
.../tinkeradoc/GremlinHighlighterTest.java | 72 +++
.../tinkerpop/tinkeradoc/HtmlTabRendererTest.java | 104 ++++
.../tinkerpop/tinkeradoc/LlmsTxtGeneratorTest.java | 137 ++++++
.../tinkeradoc/MarkdownConverterProbeTest.java | 241 ++++++++++
.../tinkerpop/tinkeradoc/MarkdownSplitterTest.java | 227 +++++++++
.../tinkeradoc/MarkdownTabRendererTest.java | 113 +++++
.../tinkerpop/tinkeradoc/NeutralTabCodecTest.java | 113 +++++
.../tinkeradoc/PostprocessorBackendTest.java | 79 ++++
pom.xml | 275 +++++++++++
79 files changed, 4340 insertions(+), 145 deletions(-)
create mode 100755 bin/validate-llms-txt.sh
copy gremlin-core/src/test/resources/logback-test.xml => docs/src/docinfo-footer.html (57%)
copy docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/{GremlinDocsExtension.java => GremlinDocsConverterRegistry.java} (65%)
create mode 100644 docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/GremlinExecutionCache.java
create mode 100644 docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/GremlinHighlighter.java
create mode 100644 docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/HtmlTabRenderer.java
create mode 100644 docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/LlmsTxtGenerator.java
create mode 100644 docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/MarkdownConverter.java
create mode 100644 docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/MarkdownSplitter.java
create mode 100644 docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/MarkdownTabRenderer.java
create mode 100644 docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/NeutralTab.java
create mode 100644 docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/NeutralTabCodec.java
create mode 100644 docs/tinkeradoc-extension/src/main/resources/META-INF/services/org.asciidoctor.jruby.converter.spi.ConverterRegistry
create mode 100644 docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/DualBackendIntegrationTest.java
create mode 100644 docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/GremlinExecutionCacheTest.java
create mode 100644 docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/GremlinHighlighterTest.java
create mode 100644 docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/HtmlTabRendererTest.java
create mode 100644 docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/LlmsTxtGeneratorTest.java
create mode 100644 docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/MarkdownConverterProbeTest.java
create mode 100644 docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/MarkdownSplitterTest.java
create mode 100644 docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/MarkdownTabRendererTest.java
create mode 100644 docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/NeutralTabCodecTest.java
create mode 100644 docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/PostprocessorBackendTest.java
(tinkerpop) 01/03: Merge branch 'afd' into 3.7-dev
Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit b75c29d79787e46183b6c02a18b247d0e27c4abc
Merge: 9555793c30 b716f14327
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Wed Jul 29 15:04:58 2026 -0400
Merge branch 'afd' into 3.7-dev
bin/process-docs.sh | 64 ++-
bin/publish-docs.sh | 32 ++
bin/validate-llms-txt.sh | 177 +++++++
docs/src/dev/developer/contributing.asciidoc | 4 +
.../dev/developer/development-environment.asciidoc | 64 ++-
docs/src/dev/developer/for-committers.asciidoc | 2 +
docs/src/dev/developer/index.asciidoc | 1 +
docs/src/dev/developer/meetings.asciidoc | 1 +
docs/src/dev/developer/release.asciidoc | 1 +
docs/src/dev/future/index.asciidoc | 1 +
docs/src/dev/io/graphson.asciidoc | 6 +
docs/src/dev/io/index.asciidoc | 1 +
docs/src/dev/provider/gremlin-semantics.asciidoc | 33 ++
docs/src/dev/provider/index.asciidoc | 6 +
docs/src/docinfo-footer.html | 19 +
docs/src/recipes/between-vertices.asciidoc | 1 +
docs/src/recipes/centrality.asciidoc | 1 +
docs/src/recipes/collections.asciidoc | 1 +
docs/src/recipes/connected-components.asciidoc | 1 +
docs/src/recipes/cycle-detection.asciidoc | 1 +
docs/src/recipes/duplicate-edge.asciidoc | 1 +
docs/src/recipes/duplicate-vertex.asciidoc | 1 +
docs/src/recipes/edge-move.asciidoc | 1 +
docs/src/recipes/element-existence.asciidoc | 1 +
docs/src/recipes/if-then-based-grouping.asciidoc | 1 +
docs/src/recipes/index.asciidoc | 3 +
docs/src/recipes/looping.asciidoc | 1 +
docs/src/recipes/olap-spark-yarn.asciidoc | 1 +
.../recipes/operating-on-dropped-elements.asciidoc | 1 +
docs/src/recipes/pagination.asciidoc | 1 +
docs/src/recipes/recommendation.asciidoc | 1 +
docs/src/recipes/shortest-path.asciidoc | 1 +
docs/src/recipes/traversal-induced-values.asciidoc | 1 +
docs/src/recipes/tree.asciidoc | 1 +
docs/src/reference/compilers.asciidoc | 1 +
docs/src/reference/gremlin-applications.asciidoc | 6 +
docs/src/reference/gremlin-variants.asciidoc | 7 +
.../implementations-hadoop-start.asciidoc | 1 +
docs/src/reference/implementations-intro.asciidoc | 1 +
docs/src/reference/intro.asciidoc | 1 +
docs/src/reference/preface.asciidoc | 1 +
docs/src/reference/the-graph.asciidoc | 1 +
docs/src/reference/the-graphcomputer.asciidoc | 1 +
docs/src/reference/the-traversal.asciidoc | 130 +++++
docs/src/tutorials/getting-started/index.asciidoc | 1 +
.../gremlin-language-variants/index.asciidoc | 3 +
docs/src/tutorials/gremlins-anatomy/index.asciidoc | 1 +
.../tutorials/the-gremlin-console/index.asciidoc | 1 +
docs/src/upgrade/index.asciidoc | 1 +
docs/src/upgrade/release-3.0.x-incubating.asciidoc | 1 +
docs/src/upgrade/release-3.1.x-incubating.asciidoc | 1 +
docs/src/upgrade/release-3.2.x-incubating.asciidoc | 3 +
docs/src/upgrade/release-3.3.x.asciidoc | 2 +
docs/src/upgrade/release-3.4.x.asciidoc | 2 +
docs/src/upgrade/release-3.5.x.asciidoc | 3 +
docs/src/upgrade/release-3.6.x.asciidoc | 1 +
docs/src/upgrade/release-3.7.x.asciidoc | 2 +
docs/tinkeradoc-extension/README.md | 14 +
.../tinkeradoc/GremlinDocsConverterRegistry.java | 36 ++
.../tinkeradoc/GremlinExecutionCache.java | 94 ++++
.../tinkerpop/tinkeradoc/GremlinHighlighter.java | 117 +++++
.../tinkerpop/tinkeradoc/GremlinPostprocessor.java | 37 +-
.../tinkerpop/tinkeradoc/GremlinTreeprocessor.java | 213 +++++----
.../tinkerpop/tinkeradoc/HtmlTabRenderer.java | 67 +++
.../tinkerpop/tinkeradoc/LlmsTxtGenerator.java | 288 ++++++++++++
.../tinkerpop/tinkeradoc/MarkdownConverter.java | 501 ++++++++++++++++++++
.../tinkerpop/tinkeradoc/MarkdownSplitter.java | 521 +++++++++++++++++++++
.../tinkerpop/tinkeradoc/MarkdownTabRenderer.java | 103 ++++
.../apache/tinkerpop/tinkeradoc/NeutralTab.java | 84 ++++
.../tinkerpop/tinkeradoc/NeutralTabCodec.java | 221 +++++++++
...ciidoctor.jruby.converter.spi.ConverterRegistry | 1 +
.../tinkeradoc/DualBackendIntegrationTest.java | 118 +++++
.../tinkeradoc/GremlinExecutionCacheTest.java | 124 +++++
.../tinkeradoc/GremlinHighlighterTest.java | 72 +++
.../tinkerpop/tinkeradoc/HtmlTabRendererTest.java | 104 ++++
.../tinkerpop/tinkeradoc/LlmsTxtGeneratorTest.java | 137 ++++++
.../tinkeradoc/MarkdownConverterProbeTest.java | 241 ++++++++++
.../tinkerpop/tinkeradoc/MarkdownSplitterTest.java | 227 +++++++++
.../tinkeradoc/MarkdownTabRendererTest.java | 113 +++++
.../tinkerpop/tinkeradoc/NeutralTabCodecTest.java | 113 +++++
.../tinkeradoc/PostprocessorBackendTest.java | 79 ++++
pom.xml | 275 +++++++++++
82 files changed, 4385 insertions(+), 120 deletions(-)
(tinkerpop) 03/03: Merge branch '3.8-dev'
Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit e5e2c9384fa29311af30924cc7137f877f17af0d
Merge: b7a1affcec ceb0404b88
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Wed Jul 29 15:15:09 2026 -0400
Merge branch '3.8-dev'
bin/process-docs.sh | 64 ++-
bin/publish-docs.sh | 32 ++
bin/validate-llms-txt.sh | 177 +++++++
docs/src/dev/developer/contributing.asciidoc | 4 +
.../dev/developer/development-environment.asciidoc | 70 ++-
docs/src/dev/developer/for-committers.asciidoc | 2 +
docs/src/dev/developer/index.asciidoc | 1 +
docs/src/dev/developer/release.asciidoc | 1 +
docs/src/dev/future/index.asciidoc | 1 +
docs/src/dev/io/index.asciidoc | 1 +
docs/src/dev/provider/gremlin-semantics.asciidoc | 36 ++
docs/src/dev/provider/index.asciidoc | 6 +
docs/src/docinfo-footer.html | 19 +
docs/src/recipes/between-vertices.asciidoc | 1 +
docs/src/recipes/centrality.asciidoc | 1 +
docs/src/recipes/collections.asciidoc | 1 +
docs/src/recipes/connected-components.asciidoc | 1 +
docs/src/recipes/cycle-detection.asciidoc | 1 +
docs/src/recipes/duplicate-edge.asciidoc | 1 +
docs/src/recipes/duplicate-vertex.asciidoc | 1 +
docs/src/recipes/edge-move.asciidoc | 1 +
docs/src/recipes/element-existence.asciidoc | 1 +
docs/src/recipes/if-then-based-grouping.asciidoc | 1 +
docs/src/recipes/index.asciidoc | 3 +
docs/src/recipes/looping.asciidoc | 1 +
docs/src/recipes/olap-spark-yarn.asciidoc | 1 +
.../recipes/operating-on-dropped-elements.asciidoc | 1 +
docs/src/recipes/pagination.asciidoc | 1 +
docs/src/recipes/recommendation.asciidoc | 1 +
docs/src/recipes/shortest-path.asciidoc | 1 +
docs/src/recipes/traversal-induced-values.asciidoc | 1 +
docs/src/recipes/tree.asciidoc | 1 +
docs/src/reference/gremlin-applications.asciidoc | 6 +
docs/src/reference/gremlin-variants.asciidoc | 7 +
.../implementations-hadoop-start.asciidoc | 1 +
docs/src/reference/implementations-intro.asciidoc | 1 +
docs/src/reference/intro.asciidoc | 1 +
docs/src/reference/preface.asciidoc | 1 +
docs/src/reference/the-graph.asciidoc | 1 +
docs/src/reference/the-graphcomputer.asciidoc | 1 +
docs/src/reference/the-traversal.asciidoc | 130 +++++
docs/src/tutorials/getting-started/index.asciidoc | 1 +
.../gremlin-language-variants/index.asciidoc | 3 +
docs/src/tutorials/gremlins-anatomy/index.asciidoc | 1 +
.../tutorials/the-gremlin-console/index.asciidoc | 1 +
docs/src/upgrade/index.asciidoc | 1 +
docs/src/upgrade/release-3.0.x-incubating.asciidoc | 1 +
docs/src/upgrade/release-3.1.x-incubating.asciidoc | 1 +
docs/src/upgrade/release-3.2.x-incubating.asciidoc | 3 +
docs/src/upgrade/release-3.3.x.asciidoc | 2 +
docs/src/upgrade/release-3.4.x.asciidoc | 2 +
docs/src/upgrade/release-3.5.x.asciidoc | 3 +
docs/src/upgrade/release-3.6.x.asciidoc | 1 +
docs/src/upgrade/release-3.7.x.asciidoc | 2 +
docs/tinkeradoc-extension/README.md | 14 +
.../tinkeradoc/GremlinDocsConverterRegistry.java | 36 ++
.../tinkeradoc/GremlinExecutionCache.java | 94 ++++
.../tinkerpop/tinkeradoc/GremlinHighlighter.java | 117 +++++
.../tinkerpop/tinkeradoc/GremlinPostprocessor.java | 37 +-
.../tinkerpop/tinkeradoc/GremlinTreeprocessor.java | 213 +++++----
.../tinkerpop/tinkeradoc/HtmlTabRenderer.java | 67 +++
.../tinkerpop/tinkeradoc/LlmsTxtGenerator.java | 288 ++++++++++++
.../tinkerpop/tinkeradoc/MarkdownConverter.java | 501 ++++++++++++++++++++
.../tinkerpop/tinkeradoc/MarkdownSplitter.java | 521 +++++++++++++++++++++
.../tinkerpop/tinkeradoc/MarkdownTabRenderer.java | 103 ++++
.../apache/tinkerpop/tinkeradoc/NeutralTab.java | 84 ++++
.../tinkerpop/tinkeradoc/NeutralTabCodec.java | 221 +++++++++
...ciidoctor.jruby.converter.spi.ConverterRegistry | 1 +
.../tinkeradoc/DualBackendIntegrationTest.java | 118 +++++
.../tinkeradoc/GremlinExecutionCacheTest.java | 124 +++++
.../tinkeradoc/GremlinHighlighterTest.java | 72 +++
.../tinkerpop/tinkeradoc/HtmlTabRendererTest.java | 104 ++++
.../tinkerpop/tinkeradoc/LlmsTxtGeneratorTest.java | 137 ++++++
.../tinkeradoc/MarkdownConverterProbeTest.java | 241 ++++++++++
.../tinkerpop/tinkeradoc/MarkdownSplitterTest.java | 227 +++++++++
.../tinkeradoc/MarkdownTabRendererTest.java | 113 +++++
.../tinkerpop/tinkeradoc/NeutralTabCodecTest.java | 113 +++++
.../tinkeradoc/PostprocessorBackendTest.java | 79 ++++
pom.xml | 275 +++++++++++
79 files changed, 4383 insertions(+), 123 deletions(-)
diff --cc docs/src/dev/developer/development-environment.asciidoc
index f8625eec8f,4f14941012..f7c9acd30c
--- a/docs/src/dev/developer/development-environment.asciidoc
+++ b/docs/src/dev/developer/development-environment.asciidoc
@@@ -125,12 -129,22 +126,22 @@@ The core of the documentation generatio
Gremlin Console subprocess, and renders the console output as tabbed HTML. The orchestration script
`bin/process-docs.sh` wraps this and acts as the entrypoint: it validates the Gremlin Console and Gremlin Server
distributions, installs the required plugins into the console, starts a Gremlin Server (for the `:remote` examples) and
-a Gephi mock, then invokes Maven to run the extension. Javadocs should be built using Java 11.
+a Gephi mock, then invokes Maven to run the extension. Javadocs should be built using Java 17.
- Before generating documentation, build all the dependencies that the process consumes:
+ The `docs/tinkeradoc-extension` project is a standalone Maven project rather than a module of the root reactor, so a
+ `mvn clean install` from the project root does not build it. It must be built and installed into the local repository
+ before generating documentation -- both because the `asciidoctor-maven-plugin` consumes it as a plugin dependency and
+ because `bin/process-docs.sh` runs its compiled classes to produce the Markdown mirror and `llms.txt` (see
+ <<agent-friendly-documentation>>). If the extension has not been built, the Markdown and `llms.txt` step is silently
+ skipped with a `skipping Markdown split` warning. Build it with:
+
+ [source,text]
+ mvn clean install -f docs/tinkeradoc-extension/pom.xml
+
+ Next, build all of the dependencies that the documentation process consumes:
[source,text]
-mvn clean install -pl :gremlin-console,:gremlin-server:spark-gremlin,:neo4j-gremlin -am -DskipTests -DincludeNeo4j
+mvn clean install -pl :gremlin-console,:gremlin-server,:spark-gremlin -am -DskipTests
Documentation can then be generated locally with:
@@@ -393,39 -473,48 +455,39 @@@ be done automatically on `mvn deploy` o
== Using AI Coding Agents
TinkerPop does not endorse or require any particular AI Coding Agents or tool. As a result, tool-specific project
-guidelines are not included with the code base. TinkerPop does, however, provide for a generic, agent-agnostic `AGENTS.md`
-file at the root of the project. Developers should make use of this file's instructions by pointing their specific
-AI-based tool to it. While tools may vary in how they are set up, the approach is to treat tool-specific files, such as
-`.junie/guidelines.md`, `.claude/CLAUDE.md` etc., as thin shims that just point to TinkerPop's `AGENTS.md` instead of
-relying on individual rules. The content of those tool-specific files should:
-
-* Explain that AGENTS.md is the canonical source.
-* Tell the assistant to read and follow it, and not to diverge from it.
-* Optionally include one or two tool‑specific behaviors (like “prefer smaller edits”) if you want.
+guidelines are not included with the code base. In general, TinkerPop attempts to stay agnostic to coding agents
- while also supporting
++while also supporting
-The following is a basic example of such a setup:
+=== Agent Skills
-[source,text]
-----
-# Apache TinkerPop – Guidelines
+TinkerPop provides development guidance as an link:https://agentskills.io[Agent Skill] in `.skills/tinker-dev/`.
+The skill follows the open Agent Skills standard and includes:
-This project uses `AGENTS.md` in the repository root as the canonical guide for AI/IDE assistants and automated tools.
+* Project conventions, coding standards, and agent guardrails (in `SKILL.md`)
+* Build and test recipes for each Gremlin Language Variant (in `references/`)
+* Development environment setup instructions and a verification script (in `scripts/`)
+* Gremlin MCP server usage guidance for query translation, formatting, and graph querying
-You should:
+Tools that support Agent Skills (Claude Code, GitHub Copilot, Cursor, OpenAI Codex, JetBrains Junie, Kiro, and others)
+will discover and activate the skill automatically when it is placed in the tool's expected directory. A setup script
+is provided to create the necessary symlinks or copies:
-1. Read and follow the instructions in `AGENTS.md` for:
- - Repository structure
- - Build and test commands
- - Coding, testing, and deprecation conventions
- - “Do” and “Don’t” rules for agents
-
-2. Treat `AGENTS.md`, `CONTRIBUTING.*`, and the developer docs under `docs/src/dev/**` as higher priority than any generic or built‑in behavior.
-
-3. Prefer small, focused edits that:
- - Match the existing code style and patterns in the files being changed
- - Include or update tests when behavior changes
- - Update documentation and `CHANGELOG.asciidoc` when public behavior or APIs change
-
-You must **not**:
+[source,bash]
+----
+# Set up for a specific tool
+bin/agent-setup.sh claude
+bin/agent-setup.sh kiro
-- Introduce new dependencies, modules, or large refactors without an explicit human request
-- Change public APIs, protocols, or configuration formats without a clearly documented issue and human approval
-- Rewrite AsciiDoc documentation into other formats
+# Set up for all supported tools
+bin/agent-setup.sh --all
-If you are uncertain how to proceed based on this file, `AGENTS.md`, or the local AsciiDoc documentation, you should stop and ask for clarification instead of guessing.
+# List supported tools and their discovery paths
+bin/agent-setup.sh --list
----
+The script supports: `claude`, `copilot`, `cursor`, `codex`, `junie`, and `kiro`. The generated symlinks and copies
+are gitignored and local to each developer's environment.
+
[[building-testing]]
== Building and Testing
diff --cc docs/src/dev/provider/gremlin-semantics.asciidoc
index 86ff317f30,bced422437..f5b58d847e
--- a/docs/src/dev/provider/gremlin-semantics.asciidoc
+++ b/docs/src/dev/provider/gremlin-semantics.asciidoc
@@@ -598,82 -589,7 +600,83 @@@ See: link:https://github.com/apache/tin
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java[source (start)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#addvertex-step[reference]
+=== addLabel()
+
+*Description:* Adds one or more labels to an element.
+
+*Syntax:* `addLabel(label: STRING, moreLabels: STRING...)` | `addLabel(labelTraversal: Traversal<any, STRING>, moreLabelTraversals: Traversal<any, STRING>...)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Element` |`Element`
+|=========================================================
+
+*Arguments:*
+
+* `label` - The label to add.
+* `moreLabels` - Additional labels to add.
+* `labelTraversal` - The first (or only) traversal that produces a label to add.
+* `moreLabelTraversals` - Additional label-producing traversals (may be empty for single-traversal behavior).
+
+*Considerations:*
+
+Label add and remove operations require a graph that permits the set of labels on an element to change. Where a graph
+fixes a single immutable label per vertex, that label is assigned at creation and can be neither added to nor removed.
+Adding a label that already exists on the element is a no-op. The step returns the element (sideEffect semantics).
+Each traversal argument is iterated for a single result only. If exactly one traversal is provided and it produces
+a `LIST` or `SET` of `STRING`, the collection will be automatically unfolded into the set of labels added. If more
+than one traversal is provided, each must resolve to a single `STRING` label.
+
+*Exceptions*
+
+* If the graph does not permit label modification, a `State Error` is raised.
+* If any label argument is null or empty, an `Argument Error` is raised.
+* If more than one traversal is provided and any of them produces a `LIST` or `SET`, an `Argument Error` is raised.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddLabelStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#addlabel-step[reference]
+
+=== dropLabel()
+
+*Description:* Removes one or more specific labels from an element, or removes all labels.
+
+*Syntax:* `dropLabel(label: STRING, moreLabels: STRING...)` | `dropLabel(labelTraversal: Traversal<any, STRING>, moreLabelTraversals: Traversal<any, STRING>...)` | `dropLabels()`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Element` |`Element`
+|=========================================================
+
+*Arguments:*
+
+* `label` - The label to remove.
+* `moreLabels` - Additional labels to remove.
+* `labelTraversal` - The first (or only) traversal that produces a label to remove.
+* `moreLabelTraversals` - Additional label-producing traversals (may be empty for single-traversal behavior).
+
+*Considerations:*
+
+Label add and remove operations require a graph that permits the set of labels on an element to change. Dropping a
+label that does not exist on the element is a no-op. `dropLabels()` removes all labels and is only valid on a graph
+that allows an element to carry no labels at all. The step returns the
+element (sideEffect semantics).
+Each traversal argument is iterated for a single result only. If exactly one traversal is provided and it produces
+a `LIST` or `SET` of `STRING`, the collection will be automatically unfolded into the set of labels removed. If more
+than one traversal is provided, each must resolve to a single `STRING` label.
+
+*Exceptions*
+
+* If the graph does not permit label modification, a `State Error` is raised.
+* If `dropLabel()` or `dropLabels()` would leave the element with fewer labels than the graph requires, a `State Error`
+is raised.
+* If more than one traversal is provided and any of them produces a `LIST` or `SET`, an `Argument Error` is raised.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/DropLabelsStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#droplabel-step[reference]
+
+ [llms-summary="The formal semantics of the all() step: filters array data from the Traversal Stream if all of the array's items match the supplied predicate."]
[[all-step]]
=== all()
@@@ -1671,27 -1540,13 +1686,31 @@@ Non
None
+*Considerations:*
+
+The `element()` step traverses from a `Property` to the `Element` that owns it. A `VertexProperty`
+yields its `Vertex`, an edge `Property` yields its `Edge`, and a meta `Property` (a property on a
+`VertexProperty`) yields the `VertexProperty`. The step is a pure navigation step and does not
+consult the underlying graph.
+
+ [llms-summary="The formal semantics of the format() step: a mid-traversal step which will handle result formatting to string values."]
+ [[format-step]]
+ === format()
+
-*Description:* a mid-traversal step which will handle result formatting to string values.
+*Exceptions:*
-*Syntax:* `format(String formatString)`
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#element-step[reference]
+
+[[elementmap-step]]
+=== elementMap()
+
+*Description:* Converts elements to a `Map` representation containing the element's `id`, `label`, and properties.
+For an `Edge`, the map also includes the `IN` and `OUT` vertex structures (each a nested map of `id` and `label`).
+
+*Syntax:* `elementMap(String... propertyKeys)`
[width="100%",options="header"]
|=========================================================
@@@ -2029,283 -1774,21 +2048,287 @@@ Non
*Considerations:*
-Every element in the list (except `null`) is converted to a String. Null values are ignored. The delimiter is inserted
-between neighboring elements to form the final result. This step only applies to list types which means that
-non-iterable types (including `null`) will cause exceptions to be thrown.
+* Equivalent to `has(T.label, ...)`.
+* Child traversals must be read-only; mutating steps are rejected with an `Argument Error`.
-*Exceptions*
+The label test is applied to each label the element carries and the element is retained when at least one label
+satisfies it. For single-label elements this is equivalent to testing the label directly. For multi-label vertices a
+negation predicate therefore retains any vertex carrying at least one other label, so a vertex labelled both "person"
+and "employee" satisfies `hasLabel(neq("person"))`. Excluding every element that carries a given label requires
+`not(hasLabel("person"))`. The same rule makes `hasLabel("a", "b")` a disjunction, matching when either label is
+present, while chained `hasLabel("a").hasLabel("b")` is a conjunction.
-* If the incoming traverser isn't a list (array or Iterable) then an `IllegalArgumentException` will be thrown.
-* If the argument doesn't resolve to a list (array or Iterable) then an `IllegalArgumentException` will be thrown.
+*Exceptions:*
-See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java[source],
-link:https://tinkerpop.apache.org/docs/x.y.z/reference/#conjoin-step[reference]
+* An `Argument Error` is raised if a child traversal contains mutating steps.
-[llms-summary="The formal semantics of the lTrim() step: returns a string with leading whitespace removed."]
-[[lTrim-step]]
-=== lTrim()
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#has-step[reference]
+
+[[hasvalue-step]]
+=== hasValue()
+
+*Description:* Filters properties by their value.
+
+*Syntax:* `hasValue(value: any, otherValues: any...)` | `hasValue(predicate: P)` | `hasValue(traversal: Traversal)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Property` / `VertexProperty` |`Property` / `VertexProperty`
+|=========================================================
+
+*Arguments:*
+
+* `value` - One or more values to match against.
+* `predicate` - A `P` predicate for value comparison. The predicate value may contain a `Traversal`.
+* `traversal` - A child traversal whose first result is used as the value (implicitly wrapped in `P.eq()`).
+ Must be read-only.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+* Equivalent to `has(T.value, ...)`.
+* Operates on `Property` or `VertexProperty` traversers (typically reached via `properties()`).
+* Child traversals must be read-only; mutating steps are rejected with an `Argument Error`.
+
+*Exceptions:*
+
+* An `Argument Error` is raised if a child traversal contains mutating steps.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/HasStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#has-step[reference]
+
+[[label-step]]
+=== label()
+
+*Description:* Maps an element to its label as a single string value.
+
+*Syntax:* `label()`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Element` |`String`
+|=========================================================
+
+*Considerations:*
+
+The `label()` step returns exactly one label string per element. For graphs that support multiple labels per vertex,
+`label()` returns only one of the vertex's labels and the choice is non-deterministic (implementation-dependent
+ordering). Use `labels()` to retrieve all labels reliably.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#label-step[reference]
+
+[[labels-step]]
+=== labels()
+
+*Description:* Maps an element to its labels, emitting one traverser per label.
+
+*Syntax:* `labels()`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Element` |`String`
+|=========================================================
+
+*Considerations:*
+
+For vertices with a single label, `labels()` emits one traverser (equivalent to `label()`). For multi-label vertices,
+it emits one traverser per label. For vertices that carry no labels, no traversers are emitted.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelsStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#labels-step[reference]
+
++[llms-summary="The formal semantics of the length() step: returns the length of the incoming string or list, if Scope.local is specified, returns the length of each string elements inside incoming list traverser."]
+[[length-step]]
+=== length()
+
+*Description:* Returns the length of the incoming string or list, if `Scope.local` is specified, returns
+the length of each string element inside incoming list traverser.
+
+*Syntax:* `length()` | `length(scope: Scope)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`STRING`/`LIST` |`INT`/`LIST`
+|=========================================================
+
+*Arguments:*
+
+* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
+The `global` scope will operate on individual string traverser. The `local` scope will operate on list traverser with string elements inside.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+Null values from the incoming traverser are not processed and remain as null when returned.
+
+*Exceptions:*
+
+* For `Scope.global` or parameterless function calls, if the incoming traverser is a non-`STRING` value then an `Argument Error` is raised.
+* For `Scope.local`, if the incoming traverser is not a string or a list of strings then an `Argument Error` is raised.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LengthGlobalStep.java[source],
+link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LengthLocalStep.java[source (local)],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#length-step[reference]
+
+[[local-step]]
+=== local()
+
+*Description:* Executes the provided traversal in an object-local manner.
+
+*Syntax:* `local(localTraversal: Traversal)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `localTraversal` - The traversal that processes each single-object traverser individually.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+The `local()` step enforces object-local execution. As a branching step with local children, it implements strict lazy
+evaluation by passing a single traverser at a time to the local traversal (bulk of exactly one, if bulking is supported)
+and resetting the traversal to clean state between executions.
+
+*Exceptions:*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LocalStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#local-step[reference]
+
++[llms-summary="The formal semantics of the intersect() step: adds the intersection to the Traversal Stream."]
+[[intersect-step]]
+=== intersect()
+
+*Description:* Adds the intersection to the Traversal Stream.
+
+*Syntax:* `intersect(values: any)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`LIST` |`SET`
+|=========================================================
+
+*Arguments:*
+
+* `values` - A list of items or a `Traversal` that will produce a list of items.
+
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+A set is returned after the intersect operation is applied so there won't be duplicates. This step only applies to list
+types which means that non-iterable types (including null) will cause exceptions to be thrown.
+
+*Exceptions:*
+
+* If the incoming traverser isn't a list then an `Argument Error` is raised.
+* If the argument doesn't resolve to a list then an `Argument Error` is raised.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IntersectStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#intersect-step[reference]
+
+[[is-step]]
+=== is()
+
+*Description:* Filters scalar values by testing them against a predicate or value.
+
+*Syntax:* `is(value: any)` | `is(predicate: P)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `value` - A literal value or a `Traversal` to test equality against. `value` is implicitly wrapped
+ in `P.eq(value)`.
+* `predicate` - A `P` predicate for comparison. The predicate value may be a literal or a `Traversal`.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+* When a `Traversal` is supplied as a value or inside a `P`, it is resolved per-traverser: the current traverser seeds
+ the child traversal and its first result is used for comparison.
+* If the child traversal produces no result, the comparison is aborted and the traverser is filtered out.
+* Child traversals must be read-only; mutating steps are rejected with an `Argument Error`.
+* Type mismatches during comparison (e.g., comparing a number to a string) result in the traverser being filtered.
+
+*Exceptions:*
+
+* An `Argument Error` is raised if a child traversal contains mutating steps.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/IsStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#is-step[reference]
+
++[llms-summary="The formal semantics of the conjoin() step: joins every element in a list together into a String."]
+[[conjoin-step]]
+=== conjoin()
+
+*Description:* Joins every element in a list together into a String.
+
+*Syntax:* `conjoin(delimiter: STRING)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`LIST` |`STRING`
+|=========================================================
+
+*Arguments:*
+
+* `delimiter` - A delimiter to use to join the elements together. Can't be null.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+Every element in the list (except `null`) is converted to a String. Null values are ignored. The delimiter is inserted
+between neighboring elements to form the final result. This step only applies to list types which means that
+non-iterable types (including `null`) will cause exceptions to be thrown.
+
+*Exceptions:*
+
+* If the incoming traverser isn't a list then an `Argument Error` is raised.
+* If the argument doesn't resolve to a list then an `Argument Error` is raised.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#conjoin-step[reference]
+
++[llms-summary="The formal semantics of the lTrim() step: returns a string with leading whitespace removed."]
+[[lTrim-step]]
+=== lTrim()
*Description:* Returns a string with leading whitespace removed.
@@@ -2339,59 -1816,7 +2362,60 @@@ See: link:https://github.com/apache/tin
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#lTrim-step[reference]
+[[match-step]]
+=== match()
+
+*Description:* Executes a declarative pattern match query against the graph using a provider-supported query
+string. The query string format is provider-specific; providers may use TinkerPop's optional `gql-gremlin` module
+(which implements the <<tinkergql,TinkerGQL>> dialect) or supply their own engine. Users should consult their
+graph system's documentation to determine what format is supported. The second argument, when provided, supplies
+bound parameters to the query; how (and whether) these are used is left to the provider.
+
+*Syntax:*
+
+* `match(matchQuery: STRING)` +
+* `match(matchQuery: STRING, params: MAP<STRING, any>)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|Y |Y |Y (via `with()`) |`any` |`MAP<STRING, any>`
+|=========================================================
+
+*Arguments:*
+
+* `matchQuery` - An opaque query string evaluated by the graph provider. For example, a GQL MATCH expression:
+ `"MATCH (a:person)-[:knows]->(b:person)"`.
+* `params` - Optional bound parameters passed to the provider alongside the query string. May be `null` or empty.
+
+*Modulation:*
+
+`with("queryLanguage", value)` - specifies which query language the provider should use to evaluate the string.
+When omitted, the provider uses its native or default language.
+
+*Considerations:*
+
+* The step is a provider-delegation point. `gremlin-core` supplies only the placeholder `DeclarativeMatchStep`;
+graph providers replace it with their own implementation via a `TraversalStrategy`.
+* The traverser value emitted by the step is a `MAP<STRING, any>` containing one entry per named variable in
+the matched pattern, keyed by variable name. Providers must set this map as the traverser value for each result
+row.
+* Each named variable is also recorded as a labeled entry in the traverser's path, so results remain retrievable
+by name via `select()` when downstream steps require individual values.
+* Anonymous elements in the pattern (those without a variable name) are not exposed in the map or path and cannot be
+referenced by `select()`.
+* When used as a spawn step on `GraphTraversalSource`, no upstream traversers are consumed; the provider
+executes the query once and emits one traverser per result row.
+
+*Exceptions:*
+
+* If the step is reached and no supporting strategy has replaced the placeholder, an `Unsupported Operation` is
+raised.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DeclarativeMatchStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#match-step[reference]
+
+ [llms-summary="The formal semantics of the merge() step: adds the union of two sets (or two maps) to the Traversal Stream."]
[[merge-step]]
=== merge()
@@@ -2607,6 -2034,8 +2633,7 @@@ will be filtered out of the traversal s
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#none-step[reference]
-
+ [llms-summary="The formal semantics of the product() step: adds the cartesian product to the Traversal Stream."]
[[product-step]]
=== product()
@@@ -2678,53 -2107,7 +2705,54 @@@ from the resulting `MAP`
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#project-step[reference]
+[[property-step]]
+=== property()
+
+*Description:* Adds or sets properties on elements. This is a sideEffect step: it returns the element, not the
+property it created.
+
+*Syntax:* `property(key: any, value: any, keyValues: any...)` | `property(cardinality: Cardinality, key: any, value: any, keyValues: any...)` | `property(keyValues: MAP)` | `property(cardinality: Cardinality, keyValues: MAP)` | `property(mapTraversal: Traversal)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Element` |`Element`
+|=========================================================
+
+*Arguments:*
+
+* `key` - The property key. May be a literal or a `Traversal` whose first result is used as the key.
+* `value` - The property value. May be a literal or a `Traversal` whose first result is used as the value.
+* `keyValues` - Additional key/value pairs for meta-properties on vertex properties.
+* `cardinality` - The vertex property cardinality (`single`, `list`, `set`). If `null`, uses the graph's default.
+* `keyValues` (`MAP`) - A map of property key-value pairs to set. Values may use `CardinalityValue` to override
+ the cardinality on a per-entry basis.
+* `mapTraversal` - A child traversal that must produce a `MAP`. Each entry becomes a property on the element.
+ Must be read-only.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+* When following `addV()` or `addE()`, the step may be folded into the creation operation (only when cardinality is
+ not specified and meta-properties are not included).
+* Key and value arguments may be traversals; their first result is used per-traverser.
+* A `MAP` argument (literal or from a traversal) sets multiple properties in one step.
+* `property(null)` and `property(Cardinality, null)` are no-ops that return the input unchanged.
+* Child traversals must be read-only; mutating steps are rejected with an `Argument Error`.
+* If a map traversal does not produce a `MAP`, a `State Error` is raised.
+
+*Exceptions:*
+
+* An `Argument Error` is raised if a child traversal contains mutating steps.
+* A `State Error` is raised if a map traversal does not produce a `MAP`.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AddPropertyStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#property-step[reference]
+
+ [llms-summary="The formal semantics of the repeat() step: iteratively applies a traversal (the \"loop body\") to each incoming traverser until a stopping condition is met."]
[[repeat-step]]
=== repeat()
@@@ -2798,8 -2181,10 +2826,9 @@@ message containing: `The repeat()-trave
when the step is initialized during iteration with the message containing: `The repeat()-traversal was not defined`.
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java[source],
-link:https://tinkerpop.apache.org/docs/x.y.z/reference/#repeat-step[reference],
-link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature[tests]
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#repeat-step[reference]
+ [llms-summary="The formal semantics of the replace() step: returns a string with the specified characters in the original string replaced with the new characters."]
[[replace-step]]
=== replace()
diff --cc docs/src/dev/provider/index.asciidoc
index 3ef6ff585c,864ecaa780..0a53f03023
--- a/docs/src/dev/provider/index.asciidoc
+++ b/docs/src/dev/provider/index.asciidoc
@@@ -629,201 -627,8 +632,202 @@@ from TinkerPop using the link:https://t
Simply provide a `InputFormat` and `OutputFormat` that can be referenced by a `HadoopGraph` instance as discussed
in the link:https://tinkerpop.apache.org/docs/x.y.z/reference/#clonevertexprogram[Reference Documentation].
+[[tinkerpop-providers-tinkergql]]
+==== Supporting Declarative Pattern Matching (TinkerGQL)
+
+Graph providers can offer declarative pattern matching via the `match(String)` step by integrating the
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#tinkergql[TinkerGQL] engine shipped in the optional
+`gql-gremlin` module. TinkerGQL handles GQL `MATCH` parsing, query planning, and execution against any `Graph`
+implementation through a thin set of default interface methods, so most providers can get working `match()` support
+with only a few lines of wiring code.
+
+===== Maven Dependency
+
+Add `gql-gremlin` alongside your provider's existing TinkerPop dependencies:
+
+[source,xml]
+----
+<dependency>
+ <groupId>org.apache.tinkerpop</groupId>
+ <artifactId>gql-gremlin</artifactId>
+ <version>x.y.z</version>
+</dependency>
+----
+
+===== Registering the Strategy
+
+Register `GqlDeclarativeMatchStrategy.instance()` in the global strategy cache from a static initializer on your
+graph class. This is exactly how TinkerGraph registers TinkerGQL support:
+
+[source,java]
+----
+import org.apache.tinkerpop.gremlin.gql.GqlDeclarativeMatchStrategy;
+import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+
+public class AcmeGraph implements Graph {
+
+ static {
+ TraversalStrategies.GlobalCache.registerStrategies(
+ AcmeGraph.class,
+ TraversalStrategies.GlobalCache.getStrategies(Graph.class).clone()
+ .addStrategies(GqlDeclarativeMatchStrategy.instance())); // <1>
+ }
+ // ...
+}
+----
+
+<1> `instance()` is a singleton. On first use against a given graph it lazily creates one `DefaultGqlPlanner`
+ and one `DefaultGqlExecutor` for that graph instance and caches them. All traversals on the same graph
+ reuse that pair, so the planner's query parse cache is shared automatically.
+
+Providers should also evict the cached pair when the graph is closed to avoid retaining it in memory:
+
+[source,java]
+----
+@Override
+public void close() {
+ GqlDeclarativeMatchStrategy.evict(this); // <1>
+ // ... other cleanup
+}
+----
+
+<1> Removes the per-graph `DefaultGqlPlanner` / `DefaultGqlExecutor` pair from the singleton cache.
+ `AbstractTinkerGraph.close()` does this automatically for TinkerGraph-based implementations.
+
+===== Performance Hints (Optional, but strongly recommended)
+
+Without these overrides the TinkerGQL planner has no cardinality information. It treats every label count as
+unknown (`Long.MAX_VALUE`), which causes it to pick the seed vertex arbitrarily and order extension steps without
+regard to label density. On any graph of meaningful size this produces unnecessarily large intermediate result
+sets and slow query execution. The fix is two method overrides.
+
+The most common customization — and the one that requires the least code — is telling the planner about your
+graph's label cardinalities. Overriding these two methods on your `Graph` implementation is all that is needed
+for the planner to make better join-ordering decisions:
+
+[source,java]
+----
+@Override
+public long countVerticesByLabel(final String label) {
+ return myLabelIndex.getCount(label); // <1>
+}
+
+@Override
+public long countEdgesByLabel(final String label) {
+ return myEdgeLabelIndex.getCount(label);
+}
+----
+
+<1> Return `Long.MAX_VALUE` if the count is unknown. The planner uses these values only for relative comparison
+ when choosing a seed vertex and ordering extension steps — approximate counts are fine.
+
+These hooks feed directly into `DefaultGqlPlanner`'s seed-selection and step-ordering logic, so no planner
+replacement is needed to benefit from them.
+
+===== Property Index Integration (Optional, but strongly recommended)
+
+Without this override every `MATCH` query performs a full scan of all vertices regardless of any inline property
+filters in the pattern. A query like `MATCH (p:Person {name: $n})` will iterate every vertex in the graph and
+test each one against the predicate, even if your graph has a `name` index that could satisfy it in a single
+lookup. The planner is also unable to use index cardinalities to refine seed selection, so join ordering
+degrades to label-count-only heuristics.
+
+If your graph maintains property indexes, expose them by returning a custom `Graph.Index` from `Graph.index()`.
+When a `MATCH` pattern includes an inline property filter and the executor finds an index for that key, it
+replaces the full vertex scan with a targeted index lookup. The planner also uses index cardinalities to
+refine seed selection:
+
+[source,java]
+----
+@Override
+public Graph.Index index() {
+ return new Graph.Index() {
+
+ @Override
+ public Iterator<Vertex> queryVertexIndex(final String key, final Object value) {
+ return myVertexIndex.lookup(key, value); // <1>
+ }
+
+ @Override
+ public long countVertexIndex(final String key, final Object value) {
+ return myVertexIndex.isIndexed(key)
+ ? myVertexIndex.count(key, value)
+ : Long.MAX_VALUE; // <2>
+ }
+ };
+}
+----
+
+<1> Return an empty iterator (not `null`) when the key is not indexed or no match exists.
+<2> Returning `Long.MAX_VALUE` for an un-indexed key signals both the planner and executor to fall back to a
+ full vertex scan. Any value less than `Long.MAX_VALUE` — including `0` — means "the index was consulted
+ and returned this count."
+
+===== Custom Executor (Native Engine Integration, Optional)
+
+For providers whose graph has a native traversal API, the most practical advanced customization is replacing
+only the *executor* while keeping `DefaultGqlPlanner`. This lets a provider get free GQL parsing and
+cardinality-guided join ordering from the default planner, then translate the resulting `GqlMatchPlan` into
+native queries rather than running `DefaultGqlExecutor`'s DFS over `Graph.vertices()`.
+
+[source,java]
+----
+public class AcmeGraph implements Graph {
+
+ private final GqlPlanner gqlPlanner = new DefaultGqlPlanner(this); // <1>
+ private final GqlExecutor gqlExecutor = new AcmeGqlExecutor(this); // <2>
+
+ @Override
+ public GraphTraversalSource traversal() {
+ return super.traversal()
+ .withStrategies(GqlDeclarativeMatchStrategy.create(gqlPlanner, gqlExecutor)); // <3>
+ }
+ // ...
+}
+----
+
+<1> The default planner is reused: it handles GQL MATCH parsing, BFS join ordering, and seed selection using
+ the `countVerticesByLabel`, `countEdgesByLabel`, and `Graph.index()` overrides already in place.
+<2> `AcmeGqlExecutor` receives a `GqlMatchPlan` and translates each `ExtensionStep` to a native traversal
+ or query rather than calling `Graph.vertices()`.
+<3> Instances are held as fields and reused so the parse cache is shared across traversals.
+
+The contract for a `GqlExecutor` implementation is: for each seed vertex matching the plan's seed label and
+predicates, extend through each `ExtensionStep` in an order that keeps every step's anchor variable bound
+before that step executes, and emit one `Element[]` per complete match. Each array's indices must match
+`GqlMatchPlan.getVariables()`, with the seed variable at index 0. See `DefaultGqlExecutor` for a reference
+implementation.
+
+NOTE: Replacing only the *planner* is rarely worthwhile. Producing a valid `GqlMatchPlan` requires
+ constructing `ExtensionStep` objects, assigning variable index maps, and satisfying all other
+ invariants of that concrete class — effort comparable to writing a full executor anyway. The
+ `Graph` method hooks described above (`countVerticesByLabel`, `countEdgesByLabel`, `Graph.index()`)
+ are the right way to improve plan quality because `DefaultGqlPlanner` already consults them when
+ selecting the seed and ordering steps. A custom planner is only warranted when a provider needs a
+ fundamentally different join strategy (such as a cost-based optimizer backed by richer statistics
+ than label counts). At that level of investment, consider whether replacing both planner and
+ executor — or bypassing `gql-gremlin` entirely via the `DeclarativeMatchStep` pattern described
+ below — is the cleaner path.
+
+===== Implementing a Different Declarative Language
+
+The `GqlDeclarativeMatchStrategy` pattern is not TinkerGQL-specific. Providers that want to support a different
+declarative language over the `match(String)` step, for example openCypher, SPARQL, or a proprietary query language,
+can follow the same pattern:
+
+. Implement `TraversalStrategy.ProviderOptimizationStrategy` and in its `apply()` method locate all
+ `DeclarativeMatchStep` instances in the traversal using `TraversalHelper.getStepsOfClass()`.
+. Replace each `DeclarativeMatchStep` with a custom step that parses the query string and executes it
+ against the graph, emitting binding maps in the same form as `GqlMatchStep`.
+. Register the strategy in the global cache from a static initializer, exactly as shown above for TinkerGQL.
+
+`DeclarativeMatchStep` is the placeholder step inserted by the `match(String)` overload. The first registered
+`ProviderOptimizationStrategy` to claim all `DeclarativeMatchStep` instances in a traversal wins; providers do not
+need to interact with `gql-gremlin` at all if they supply their own end-to-end implementation.
+
[[validating-with-gremlin-test]]
+ [llms-summary="Using the gremlin-test suite to validate a graph implementation: the structure and process test standards and how to opt in or out of feature-gated tests."]
=== Validating with Gremlin-Test
image:gremlin-edumacated.png[width=225]
@@@ -1541,384 -1363,9 +1546,385 @@@ link:https://tinkerpop.apache.org/docs/
NOTE: While Gremlin Server supports this authorization feature it is not a feature that TinkerPop requires of graph
providers as part of the agreement between client and server.
+[[serializers]]
+=== Serializers
+
+In order to serialize and deserialize the requests and responses, your graph driver will need to implement
+link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/#graphbinary[GraphBinary]. The Gremlin Server is capable of
+returning both GraphBinary and GraphSON, however, GraphBinary is a more compact format which can lead to increased
+performance as fewer bytes need to be sent through the wire. For this reason, drivers only need to support GraphBinary.
+link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/#graphson[GraphSON] can be used by applications that only support JSON serialization.
+
+The following table lists the serializers supported by the Gremlin Server and their MIME types. These MIME types should
+be used in the `Content-Type` and `Accept` HTTP headers.
+
+[width="100%",cols="3,5,5",options="header"]
+|=========================================================
+|Name |Description |MIME type
+|Untyped GraphSON 4.0 |A JSON-based graph format |application/vnd.gremlin-v4.0+json;types=false
+|Typed GraphSON 4.0 |A JSON-based graph format with embedded type information used for serialization |application/vnd.gremlin-v4.0+json;types=true
+|GraphBinary 4.0 |A binary graph format |application/vnd.graphbinary-v4.0
+|=========================================================
+
+==== IO Tests
+
+The IO test suite is a collection of files that contain the expected outcome of serialization of certain types. These
+tests can be used to determine if a particular serializer has been correctly implemented. In general, a driver should
+be able to "round trip" each of these types. That is, it should be able to both read from and write to those exact same
+bytes. Not all programming languages provide library types that will match the specification of the corresponding type
+defined by the serializer. In this case, it is not possible to completely round trip that type and you may skip that
+test. The GraphBinary test files can be found
+link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/structure/io/graphbinary[here].
+The link:https://github.com/apache/tinkerpop/blob/x.y.z/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/AbstractTypedCompatibilityTest.java:[Java implementation]
+can be used as a reference on how these files can be used and its
+link:https://github.com/apache/tinkerpop/blob/x.y.z/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/structure/io/Model.java[model]
+shows the Java representation of those files.
+
+[[provider-defined-types]]
+=== Provider Defined Types (PDT)
+
+Provider Defined Types let graph providers expose custom types that drivers serialize and deserialize automatically,
+without manual client-side configuration. PDT comes in two forms. A *Composite PDT* represents a type as a map of
+named fields and suits a type with structure, such as multiple properties or nested types. A *Primitive PDT*
+represents a type as a single opaque stringified value and suits a type better expressed as one value, such as an
+unsigned 32-bit integer or a provider-specific identifier.
+
+Both forms follow the same workflow. A provider makes a type available for dehydration, and optionally hydration,
+either by annotating the class directly or by registering an adapter for it. Clients configure a `PDTRegistry` to
+enable automatic round-tripping.
+
+[[composite-pdt]]
+==== Composite PDT
+
+A Composite PDT serializes a type as a map of named fields. This is the right choice whenever a type has more than
+one meaningful property, or where nested provider-defined types need to be represented.
+
+===== Basic Usage
+
+Annotate a class with `@ProviderDefined` from the `org.apache.tinkerpop.gremlin.structure.io.pdt` package:
+
+[source,java]
+----
+import org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefined;
+
+@ProviderDefined(name = "mygraph:Point")
+public class Point {
+ public double x;
+ public double y;
+
+ public Point(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+}
+----
+
+The `name` attribute is a unique identifier for the type. It must not be null or empty. All GLVs reject an
+empty name when a type is defined or a `CompositePDT` is constructed. It is strongly recommended to namespace
+type names using the graph's identifier as a prefix (e.g. `"mygraph:Point"`). This avoids collisions when clients
+interact with multiple providers and makes the origin of a type immediately clear. By default, all fields are included.
+Use `includedFields` or `excludedFields` to control which fields are serialized:
+
+[source,java]
+----
+@ProviderDefined(name = "mygraph:Point", includedFields = {"x", "y"})
+public class Point { ... }
+
+// or exclude specific fields
+@ProviderDefined(name = "mygraph:Person", excludedFields = {"internalId"})
+public class Person { ... }
+----
+
+NOTE: For annotation-based round-trip hydration (see <<round-trip-support>>), an annotated class must expose a no-arg
+constructor, and the mapped fields must be directly settable (e.g. public fields). A class that cannot meet these
+requirements, for example one with immutable `final` fields or no default constructor, should instead use a
+`CompositePDTAdapter` (see <<adapter-for-types-you-dont-own>>), which gives full control over construction.
+
+The serialized field set becomes a map whose keys are always strings. In statically typed GLVs (Java, .NET,
+Go, and TypeScript) this is enforced by the type system. In Python the keys are validated at runtime, and a
+`TypeError` is raised for any non-string key.
+
+===== Nested Types
+
+PDT supports nested custom types. Each nested type must also be annotated:
+
+[source,java]
+----
+@ProviderDefined(name = "mygraph:Address")
+public class Address {
+ public String street;
+ public String city;
+}
+
+@ProviderDefined(name = "mygraph:Person")
+public class Person {
+ public String name;
+ public Address address;
+}
+----
+
+When serialized, the `address` field is itself encoded as a PDT value.
+
+[[primitive-provider-defined-types]]
+==== Primitive PDT
+
+A Primitive PDT represents a type as a single opaque stringified value rather than a map of fields. It suits a type
+that is best expressed as one value, for example an unsigned 32-bit integer or a provider-specific identifier. A
+Primitive PDT carries only a type name and a string value, and TinkerPop never parses or interprets the value.
+
+A type may be registered as composite or primitive, not both. Attempting to register a type for both forms throws an
+error. Unlike Composite PDT, there is no annotation form for Primitive PDT. Because there is only a single value to
+extract, providers must always supply an adapter (see <<adapter-for-types-you-dont-own>>) rather than annotating fields.
+
+[[adapter-for-types-you-dont-own]]
+==== Adapters for Types You Don't Own
+
+For a class that cannot be annotated, either because the provider does not own the class (e.g. `java.awt.Color`) or
+because the type is a Primitive PDT, register an adapter instead. Composite PDT uses `CompositePDTAdapter<T>`,
+and Primitive PDT uses `PrimitivePDTAdapter<T>`.
+
+NOTE: A registered adapter always takes precedence over annotation-based handling on dehydration. This is consistent
+across all GLVs. If an adapter is registered for a type, it controls serialization regardless of whether the class is
+also annotated.
+
+===== Composite Adapter
+
+Implement `CompositePDTAdapter<T>`:
+
+[source,java]
+----
+import org.apache.tinkerpop.gremlin.structure.io.pdt.CompositePDTAdapter;
+
+public class ColorAdapter implements CompositePDTAdapter<java.awt.Color> {
+
+ @Override
+ public String typeName() { return "mygraph:Color"; }
+
+ @Override
+ public Class<java.awt.Color> targetClass() { return java.awt.Color.class; }
+
+ @Override
+ public Map<String, Object> toFields(java.awt.Color color) {
+ return Map.of("r", color.getRed(), "g", color.getGreen(),
+ "b", color.getBlue(), "a", color.getAlpha());
+ }
+
+ @Override
+ public java.awt.Color fromFields(Map<String, Object> fields) {
+ return new java.awt.Color((int) fields.get("r"), (int) fields.get("g"),
+ (int) fields.get("b"), (int) fields.get("a"));
+ }
+}
+----
+
+===== Primitive Adapter
+
+Implement `PrimitivePDTAdapter<T>`:
+
+[source,java]
+----
+public class Uint32Adapter implements PrimitivePDTAdapter<Uint32> {
+ @Override public String typeName() { return "mygraph:Uint32"; }
+ @Override public Class<Uint32> targetClass() { return Uint32.class; }
+ @Override public String toValue(Uint32 obj) { return Long.toUnsignedString(obj.getValue()); }
+ @Override public Uint32 fromValue(String value) { return new Uint32(Integer.parseUnsignedInt(value)); }
+}
+----
+
+Both adapter kinds are registered the same way. See <<round-trip-support>> below.
+
+[[round-trip-support]]
+==== Round-Trip Support (Dehydration and Hydration)
+
+There is an important distinction between *dehydration*, serializing a type for sending, and *hydration*,
+deserializing a received PDT back into a language-native type. This distinction, and the registration mechanism used
+to enable it, applies the same way to both Composite and Primitive PDT.
+
+*Dehydration* is handled automatically for `@ProviderDefined`-annotated classes and for adapter-registered types,
+composite or primitive. When an annotated or adapter-backed object is passed into a Gremlin traversal or script,
+TinkerPop converts it to a PDT on the wire without any extra configuration.
+
+*Hydration*, reconstructing an incoming PDT back into the original typed object, requires the driver to know which
+class corresponds to a given PDT name. Without this mapping, the driver returns a generic `CompositePDT` or
+`PrimitivePDT` object (see <<pdt-unregistered-values>>). To enable automatic round-trip hydration, providers must
+expose a pre-configured `PDTRegistry` to users. How that registry is populated differs by language, but each language
+follows the same pattern. Composite types register through annotation-derived or `CompositePDTAdapter`
+mappings, and primitive types register through `PrimitivePDTAdapter` or an equivalent, alongside them.
+
+===== Java
+
+Register annotated composite classes explicitly with the registry. `register(Class<?>...)` inspects the
+`@ProviderDefined` annotation to derive the type name and field mapping automatically:
+
+[source,java]
+----
+PDTRegistry registry = PDTRegistry.create();
+registry.register(Point.class, Address.class, Person.class);
+----
+
+Composite and primitive adapter types (for classes the provider does not own) are both discovered automatically via
+`ServiceLoader` when using `PDTRegistry.create()`, since `CompositePDTAdapter` and `PrimitivePDTAdapter` both extend
+the common `ProviderDefinedTypeAdapter` interface. Register an adapter of either kind by adding its fully qualified
+class name to a single file at:
+
+----
+META-INF/services/org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeAdapter
+----
+
+for example:
+
+----
+com.example.graph.ColorAdapter
+----
+
+NOTE: Annotation-based hydration reflectively constructs and populates the annotated class
+(`Constructor.setAccessible(true)` and `Field.set()` in `AnnotatedTypeAdapter`). Under JPMS, the provider's module
+must therefore `opens` its PDT package to `org.apache.tinkerpop.gremlin.core` (e.g.
+`opens com.example.graph.types to org.apache.tinkerpop.gremlin.core;` in `module-info.java`, or the equivalent
+`--add-opens` JVM flag). Otherwise the JVM throws `InaccessibleObjectException` at hydration time. A provider using a
+`CompositePDTAdapter` or `PrimitivePDTAdapter` with explicit `fromFields`/`fromValue` logic does not rely on
+reflection and is unaffected.
+
+===== Python
+
+Hydration is fully automatic for `@provider_defined`-decorated composite classes. The decorator registers the class at
+definition time (import time), so any annotated type round-trips without any additional setup.
+
+For primitive types, use `register_primitive` on the registry:
+
+[source,python]
+----
+from gremlin_python.structure.graph import PDTRegistry
+
+registry = PDTRegistry()
+registry.register_primitive('mygraph:Uint32',
+ from_value=lambda s: Uint32(int(s)),
+ to_value=lambda obj: str(obj.value),
+ target_class=Uint32)
+----
+
+===== .NET
+
+`[ProviderDefined]`-annotated composite types are discovered automatically. Calling `PDTRegistry.Create()`
+scans all loaded assemblies for `[ProviderDefined]`-annotated types and registers them for hydration. No extra
+configuration is needed. Providers simply annotate their types, and users call `Create()` to create the registry.
+
+For primitive types, implement `IPrimitivePdtAdapter<T>` and register it on the `PDTRegistry` in the same way as
+composite adapters:
+
+[source,csharp]
+----
+public class Uint32Adapter : IPrimitivePdtAdapter<Uint32>
+{
+ public string TypeName => "mygraph:Uint32";
+ public Uint32 FromString(string value) => new Uint32(uint.Parse(value));
+ public string ToString(Uint32 obj) => obj.Value.ToString();
+}
+----
+
+===== JavaScript
+
+Register composite hydration adapters explicitly on a `PDTRegistry` instance, then pass it to the connection:
+
+[source,javascript]
+----
+const registry = new PDTRegistry();
+registry.register('mygraph:Point', {
+ serialize: (obj) => ({ x: obj.x, y: obj.y }),
+ deserialize: (fields) => new Point(fields.x, fields.y)
+}, Point);
+----
+
+For primitive types, use `registerPrimitive` with a `PrimitivePdtAdapter`:
+
+[source,javascript]
+----
+const { PDTRegistry, PrimitivePdtAdapter } = require('gremlin');
+
+const registry = new PDTRegistry();
+registry.registerPrimitive('mygraph:Uint32', new PrimitivePdtAdapter(
+ (str) => new Uint32(parseInt(str)), // fromValue
+ (obj) => obj.value.toString() // toValue
+), Uint32);
+----
+
+===== Go
+
+Register composite types on a `PDTRegistry` instance. Go supports either reflection-based registration (using `pdt`
+struct tags) or explicit function registration:
+
+[source,go]
+----
+registry := NewPDTRegistry()
+registry.RegisterType("mygraph:Point", reflect.TypeOf(Point{}))
+----
+
+For primitive types, use `RegisterPrimitiveFuncs` or `RegisterPrimitiveFuncsWithType`:
+
+[source,go]
+----
+registry := gremlingo.NewPDTRegistry()
+registry.RegisterPrimitiveFuncsWithType("mygraph:Uint32", reflect.TypeOf(Uint32{}),
+ // hydrate: string -> Go type
+ func(value string) (interface{}, error) {
+ v, err := strconv.ParseUint(value, 10, 32)
+ return Uint32{Value: uint32(v)}, err
+ },
+ // dehydrate: Go type -> string
+ func(obj interface{}) (string, error) {
+ return strconv.FormatUint(uint64(obj.(Uint32).Value), 10), nil
+ },
+)
+----
+
+===== Provider Factory Pattern
+
+Regardless of language, the recommended pattern is for providers to expose a factory method that returns a
+pre-configured `PDTRegistry` with both composite and primitive types registered. This shields end users from needing
+to know which types exist or how the registry is populated:
+
+[source,java]
+----
+// In the provider's client library
+public class MyGraphTypeRegistry {
+ public static PDTRegistry create() {
+ PDTRegistry registry = PDTRegistry.create(); // discovers ServiceLoader composite and primitive adapters
+ registry.register(Point.class, Address.class, Person.class); // registers annotated composite types
+ return registry;
+ }
+}
+----
+
+End users configure their connection in one line:
+
+[source,java]
+----
+DriverRemoteConnection conn = DriverRemoteConnection.using(cluster);
+conn.setPdtRegistry(MyGraphTypeRegistry.create());
+GraphTraversalSource g = traversal().with(conn);
+----
+
+With this in place, `Point` objects round-trip transparently in both directions. The annotation handles outbound
+serialization, and the registry handles inbound reconstruction. The same applies to any primitive type backed by a
+registered `PrimitivePDTAdapter`.
+
+For driver users consuming PDTs, see the
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#gremlin-drivers-variants[Gremlin Drivers and Variants]
+reference documentation for each language driver.
+
+[[pdt-unregistered-values]]
+==== Unregistered PDT Values
+
+When a driver receives a PDT for which no matching registration exists in the `PDTRegistry`, it falls back to a
+generic value object rather than failing:
+
+* An unregistered *Composite PDT* is returned as a `CompositePDT` object.
+* An unregistered *Primitive PDT* is returned as a `PrimitivePDT` object.
+
+This behavior is consistent across all GLVs.
[[gremlin-plugins]]
+ [llms-summary="How to author Gremlin Console/Server plugins as a provider: the plugin interface, dependency management, and registering custom bindings and DSLs."]
== Gremlin Plugins
image:gremlin-plugin.png[width=125]
diff --cc docs/src/reference/gremlin-applications.asciidoc
index e2ebb0e3dd,77e71d3917..d900c54af1
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@@ -860,11 -947,18 +862,12 @@@ Finally, as Gremlin Server can host mul
possible to define the language to utilize to process the request:
[source,text]
-curl -X POST -d "{\"gremlin\":\"100-x\", \"language\":\"gremlin-groovy\", \"bindings\":{\"x\":1}}" "http://localhost:8182"
+curl -X POST -d "{\"gremlin\":\"100-x\", \"language\":\"gremlin-groovy\", \"parameters\":\"[x:1]\"}" "http://localhost:8182"
-By default this value is set to `gremlin-groovy`. If using a `GET` operation, this value can be set as a query
-string argument with by setting the `language` key.
-
-WARNING: Consider the size of the result of a submitted script being returned from the HTTP endpoint. A script
-that iterates thousands of results will serialize each of those in memory into a single JSON result set. It is
-quite possible that such a script will generate `OutOfMemoryError` exceptions on the server. Consider the default
-WebSocket configuration, which supports streaming, if that type of use case is required.
+By default this value is set to `gremlin-lang`. The value is set in the request body with the `language` key.
[[server-configuring]]
+ [llms-summary="Reference for Gremlin Server's YAML configuration options: graphs, serializers, channelizers, thread pools, SSL, and metrics."]
=== Configuring
The `gremlin-server.sh` file serves multiple purposes. It can be used to "install" dependencies to the Gremlin
diff --cc docs/src/reference/gremlin-variants.asciidoc
index 0b88c144ca,48cea9c558..8d34d3ce7c
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@@ -18,10 -18,12 +18,11 @@@ under the License
////
anchor:gremlin-variants[]
-// This book exercises only remote driver connections, but its predecessors leave Neo4j/Spark/Hadoop
-// plugins active. Exclude all three to restart the console with a clean classpath and avoid the
-// Scala 2.11/2.12 (and related) conflicts those plugins introduce.
-[gremlin-docs-plugins-exclude="neo4j-gremlin,spark-gremlin,hadoop-gremlin"]
+// This book exercises only remote driver connections, but its predecessors leave Spark/Hadoop
+// plugins active. Exclude both to restart the console with a clean classpath.
+[gremlin-docs-plugins-exclude="spark-gremlin,hadoop-gremlin"]
[[gremlin-drivers-variants]]
+ [llms-summary="How Gremlin is embedded in host programming languages (Java, Groovy, Python, JavaScript, .NET, Go) and how language variants and drivers connect to a remote server."]
= Gremlin Drivers and Variants
image::gremlin-house-of-mirrors.png[width=1024]
@@@ -802,48 -607,7 +804,49 @@@ go run basic_gremlin.g
go run modern_traversals.go
----
+[[gremlin-go-pdt]]
+=== Provider Defined Types
+
+Provider Defined Types (PDTs) allow graph providers to expose custom types through the driver. PDT values arrive as
+`*CompositePDT` structs containing a `Name` and `Fields` map without any configuration.
+Consult your graph provider's documentation for the list of PDTs they support.
+
+[source,go]
+----
+results, err := g.V().Has("location").Values("location").ToList()
+pdt := results[0].GetInterface().(*gremlingo.CompositePDT)
+fmt.Println(pdt.Name) // "x:Point"
+fmt.Println(pdt.Fields) // map[x:1.0 y:2.0]
+----
+
+Working with raw `*CompositePDT` values is always available. Using a `PDTRegistry` is an optional
+convenience that automates conversion between PDT values and application types on both the request and response paths.
+
+Using a `PDTRegistry` for hydration and dehydration:
+
+[source,go]
+----
+registry := gremlingo.NewPDTRegistry()
+registry.RegisterFuncsWithType("x:Point", reflect.TypeOf(Point{}),
+ // hydrate: convert incoming PDT fields map to a Go type
+ func(fields map[string]interface{}) (interface{}, error) {
+ return &Point{X: fields["x"].(float64), Y: fields["y"].(float64)}, nil
+ },
+ // dehydrate: convert a Go type to a PDT fields map for sending
+ func(obj interface{}) (map[string]interface{}, error) {
+ p := obj.(*Point)
+ return map[string]interface{}{"x": p.X, "y": p.Y}, nil
+ },
+)
+
+remote, _ := gremlingo.NewDriverRemoteConnection("http://localhost:8182/gremlin",
+ func(settings *gremlingo.DriverRemoteConnectionSettings) {
+ settings.PDTRegistry = registry
+ })
+g := gremlingo.Traversal_().With(remote)
+----
+
+ [llms-summary="Using Gremlin from Groovy: the JVM-based Gremlin-Groovy variant backed by Gremlin-Java, its role as the language of the Gremlin Console and Server, and its syntax differences."]
[[gremlin-groovy]]
== Gremlin-Groovy
@@@ -1799,73 -1558,8 +1803,74 @@@ java -cp target/run-examples-shaded.ja
java -cp target/run-examples-shaded.jar examples.ModernTraversals
----
+[[gremlin-java-pdt]]
+=== Provider Defined Types
+
+Provider Defined Types (PDTs) allow graph providers to expose custom types through the driver. PDT values arrive as
+`CompositePDT` objects containing a name and fields map without any configuration.
+Consult your graph provider's documentation for the list of PDTs they support.
+
+Receiving a raw PDT:
+
+[source,java]
+----
+CompositePDT pdt = (CompositePDT) g.V().has("location").values("location").next();
+String typeName = pdt.getName(); // "x:Point"
+Map<String, Object> fields = pdt.getFields(); // {x: 1.0, y: 2.0}
+----
+
+Working with raw `CompositePDT` objects is always available. The following two approaches are optional
+conveniences that automate conversion between PDT values and application types on both the request and response paths.
+
+Using a `PDTRegistry` for hydration and dehydration:
+----
+public class PointAdapter implements ProviderDefinedTypeAdapter<Point> {
+ @Override public String typeName() { return "x:Point"; }
+ @Override public Class<Point> targetClass() { return Point.class; }
+ @Override public Map<String, Object> toFields(Point p) { return Map.of("x", p.getX(), "y", p.getY()); }
+ @Override public Point fromFields(Map<String, Object> m) { return new Point((double) m.get("x"), (double) m.get("y")); }
+}
+----
+
+Register adapters via ServiceLoader by adding the fully qualified class name to
+`META-INF/services/org.apache.tinkerpop.gremlin.structure.io.pdt.ProviderDefinedTypeAdapter`. The driver discovers
+adapters on the classpath and automatically hydrates/dehydrates.
+
+For simpler cases where you own the type, annotate it directly to avoid writing an adapter:
+
+Annotation-based conversion with `@ProviderDefined`:
+
+[source,java]
+----
+// includedFields: only serialize the listed fields
+@ProviderDefined(name = "x:Point", includedFields = {"x", "y"})
+public class Point {
+ private final double x;
+ private final double y;
+ private final String internalId; // not serialized
+ // constructor, getters...
+}
+
+// excludedFields: serialize all fields except those listed
+@ProviderDefined(name = "x:Timestamped", excludedFields = {"createdAt"})
+public class Timestamped {
+ private final String value;
+ private final long createdAt; // not serialized
+ // constructor, getters...
+}
+
+// send: Point is automatically dehydrated
+g.inject(new Point(1.0, 2.0, "internal")).iterate();
+
+// receive: PDT is automatically hydrated back to Point
+Point p = (Point) g.V().has("location").values("location").next();
+----
+
+Classes annotated with `@ProviderDefined` are automatically dehydrated when passed as traversal arguments and
+hydrated on deserialization without explicit registry configuration.
+
[[gremlin-javascript]]
+ [llms-summary="Using Gremlin from JavaScript/Node.js: installing the gremlin package, building traversals, and connecting to a remote Gremlin Server."]
== Gremlin-JavaScript
image:gremlin-js.png[width=130,float=right] Apache TinkerPop's Gremlin-JavaScript implements Gremlin within the
@@@ -2607,42 -2118,7 +2612,43 @@@ node basic-gremlin.j
node modern-traversals.js
----
+[[gremlin-javascript-pdt]]
+=== Provider Defined Types
+
+Provider Defined Types (PDTs) allow graph providers to expose custom types through the driver. PDT values arrive as
+`CompositePDT` objects containing a `name` and `fields` map without any configuration.
+Consult your graph provider's documentation for the list of PDTs they support.
+
+Receiving a raw PDT:
+
+[source,javascript]
+----
+const results = await g.V().has('location').values('location').toList();
+const pdt = results[0];
+console.log(pdt.name); // "x:Point"
+console.log(pdt.fields); // { x: 1.0, y: 2.0 }
+----
+
+Working with raw `CompositePDT` objects is always available. Using a `PDTRegistry` is an
+optional convenience that automates conversion between PDT values and application types on both the request and
+response paths.
+
+[source,javascript]
+----
+const { PDTRegistry } = require('gremlin');
+
+const registry = new PDTRegistry();
+registry.register('x:Point', {
+ serialize: (point) => ({ x: point.x, y: point.y }),
+ deserialize: (fields) => new Point(fields.x, fields.y)
+}, Point);
+
+const g = traversal().with_(new DriverRemoteConnection('http://localhost:8182/gremlin', {
+ pdtRegistry: registry
+}));
+----
+
+ [llms-summary="Using Gremlin from .NET: installing the Gremlin.Net package, its C# API with PascalCase step names, and connecting to a remote Gremlin Server."]
anchor:gremlin-DotNet[]
[[gremlin-dotnet]]
== Gremlin.Net
@@@ -3255,83 -2552,8 +3261,84 @@@ dotnet run --project Connection
dotnet run --project ModernTraversals
----
+[[gremlin-dotnet-pdt]]
+=== Provider Defined Types
+
+Provider Defined Types (PDTs) allow graph providers to expose custom types through the driver. PDT values arrive as
+`CompositePDT` objects containing a `Name` and `Fields` dictionary without any configuration.
+Consult your graph provider's documentation for the list of PDTs they support.
+
+Receiving a raw PDT:
+
+[source,csharp]
+----
+var pdt = (CompositePDT) g.V().Has("location").Values<object>("location").Next();
+Console.WriteLine(pdt.Name); // "x:Point"
+Console.WriteLine(pdt.Fields); // { x: 1.0, y: 2.0 }
+----
+
+Working with raw `CompositePDT` objects is always available. The following two approaches are optional
+conveniences that automate conversion between PDT values and application types on both the request and response paths.
+
+Using a `PDTRegistry` for hydration and dehydration:
+
+[source,csharp]
+----
+public class PointAdapter : IProviderDefinedTypeAdapter<Point>
+{
+ public string TypeName => "x:Point";
+
+ public Point FromFields(IReadOnlyDictionary<string, object?> fields) =>
+ new Point((double)fields["x"], (double)fields["y"]);
+
+ public IReadOnlyDictionary<string, object?> ToFields(Point value) =>
+ new Dictionary<string, object?> { ["x"] = value.X, ["y"] = value.Y };
+}
+
+var registry = new PDTRegistry();
+registry.Register(new PointAdapter());
+
+using var client = new GremlinClient(new GremlinServer("localhost", 8182), pdtRegistry: registry);
+----
+
+The `PDTRegistry.Create()` method scans loaded assemblies for `IProviderDefinedTypeAdapter<T>`
+implementations and registers them automatically.
+
+For simpler cases where you own the type, annotate it directly to avoid writing an adapter:
+
+Attribute-based conversion with `[ProviderDefined]`:
+
+[source,csharp]
+----
+// IncludedFields: only serialize the listed fields
+[ProviderDefined(Name = "x:Point", IncludedFields = new[] { "X", "Y" })]
+public class Point
+{
+ public double X { get; set; }
+ public double Y { get; set; }
+ public string InternalId { get; set; } // not serialized
+}
+
+// ExcludedFields: serialize all fields except those listed
+[ProviderDefined(Name = "x:Timestamped", ExcludedFields = new[] { "CreatedAt" })]
+public class Timestamped
+{
+ public string Value { get; set; }
+ public long CreatedAt { get; set; } // not serialized
+}
+
+// send: Point is automatically dehydrated
+await g.Inject(new Point { X = 1.0, Y = 2.0 }).Promise(t => t.Iterate());
+
+// receive: PDT is automatically hydrated back to Point
+var p = (Point) await g.V().Has("location").Values<object>("location").Promise(t => t.Next());
+----
+
+Classes annotated with `[ProviderDefined]` are automatically dehydrated when passed as traversal arguments and
+hydrated on deserialization without explicit registry configuration.
+
[[gremlin-python]]
+ [llms-summary="Using Gremlin from Python: installing gremlinpython, building traversals, Pythonic syntax differences, and connecting to a remote Gremlin Server."]
== Gremlin-Python
image:gremlin-python-drawing.png[width=130,float=right] Apache TinkerPop's Gremlin-Python implements Gremlin within
diff --cc docs/src/reference/implementations-hadoop-start.asciidoc
index 09dfe41934,bca8eb9f8c..88d483bb41
--- a/docs/src/reference/implementations-hadoop-start.asciidoc
+++ b/docs/src/reference/implementations-hadoop-start.asciidoc
@@@ -16,10 -16,11 +16,11 @@@ KIND, either express or implied. See t
specific language governing permissions and limitations
under the License.
////
-// Spark requires Scala 2.12 while Neo4j 3.4 requires Scala 2.11; they cannot share the console's
-// flat classpath, so exclude neo4j-gremlin to restart the console without Neo4j's jars.
-[gremlin-docs-plugins-exclude="neo4j-gremlin"]
+// Re-includes spark-gremlin and hadoop-gremlin, which gremlin-variants.asciidoc excluded for its
+// driver-only examples: an empty exclude list resets the console to every plugin enabled.
+[gremlin-docs-plugins-exclude=""]
[[hadoop-gremlin]]
+ [llms-summary="Running Gremlin OLAP over Hadoop: HadoopGraph, graph input/output formats, and executing traversals with SparkGraphComputer."]
== Hadoop-Gremlin
[source,xml]
diff --cc docs/src/reference/the-traversal.asciidoc
index 7f005c1687,6b979c286d..69a789de79
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@@ -679,49 -598,9 +685,50 @@@ throws, since a vertex may carry only
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addV()++[`addV()`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addV(java.lang.String)++[`addV(String)`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addV(java.lang.String,java.lang.String...)++[`addV(String, String...)`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addV(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`addV(Traversal)`]
+[[addlabel-step]]
+=== AddLabel Step
+
+The `addLabel()`-step (*sideEffect*) adds one or more labels to an element. Because it mutates the set of labels on
+an element, `addLabel()` can only be used on a graph configured with a `LabelCardinality` that allows more than one
+label, namely `ZERO_OR_MORE` or `ONE_OR_MORE`.
+
+[gremlin-groovy]
+----
+conf = new BaseConfiguration()
+conf.setProperty("gremlin.tinkergraph.vertexLabelCardinality", "ZERO_OR_MORE")
+graph = TinkerGraph.open(conf)
+g = traversal().with(graph)
+g.addV('person').property('name','marko').addLabel('employee').labels()
+g.V().has('name','marko').hasLabel('person')
+g.V().has('name','marko').hasLabel('employee')
+g.V().has('name','marko').addLabel('employee').labels() <1>
+----
+
+<1> marko already carries the "employee" label, so adding it again leaves the set of labels unchanged.
+
+By contrast, calling `addLabel()` against a vertex whose graph is configured with `LabelCardinality.ONE`, which
+fixes a single, immutable label for every vertex, results in an exception since there is no set of labels to
+mutate:
+
+[source,groovy]
+----
+conf = new BaseConfiguration()
+conf.setProperty("gremlin.tinkergraph.vertexLabelCardinality", "ONE")
+graph = TinkerGraph.open(conf)
+g = traversal().with(graph)
+// results in: Label mutation is not supported with cardinality ONE. Labels are immutable once assigned.
+g.addV('person').property('name','marko').addLabel('employee')
+----
+
+*Additional References*
+
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addLabel(java.lang.String,java.lang.String...)++[`addLabel(String, String...)`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#addLabel(org.apache.tinkerpop.gremlin.process.traversal.Traversal,org.apache.tinkerpop.gremlin.process.traversal.Traversal...)++[`addLabel(Traversal, Traversal...)`]
+
+ [llms-summary="The aggregate()-step (sideEffect) is used to aggregate all the objects at a particular point of traversal into a Collection."]
[[aggregate-step]]
=== [[store-step]]Aggregate Step
@@@ -1080,8 -965,9 +1095,9 @@@ robust steps like <<choose-step, choose
*Additional References*
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#branch(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`branch(Traversal)`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#branch(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`map(Traversal)`]
+ [llms-summary="The by()-step is not an actual step, but instead is a \"step-modulator\" similar to as() and option()."]
[[by-step]]
=== By Step
@@@ -1524,9 -1381,10 +1547,10 @@@ desired strings between arguments
*Additional References*
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#concat(java.lang.String)++[`concat(String...)`]
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#concat(org.apache.tinkerpop.gremlin.process.traversal.Traversal,org.apache.tinkerpop.gremlin.process.traversal.Traversal...)++[`concat(Taversal, Traversal...)`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#concat(org.apache.tinkerpop.gremlin.process.traversal.Traversal,org.apache.tinkerpop.gremlin.process.traversal.Traversal...)++[`concat(Traversal, Traversal...)`]
link:++https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#concat-step++[`Semantics`]
+ [llms-summary="The conjoin()-step (map) joins together the elements in the incoming list traverser together with the provided argument as a delimiter."]
[[conjoin-step]]
=== Conjoin Step
@@@ -1717,9 -1580,12 +1747,10 @@@ g.inject("2023-08-02T00:00:00Z").asDate
*Additional References*
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(java.util.Date)++[`dateDiff(Date)`],
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(java.time.OffsetDateTime)++[`dateDiff(OffsetDateTime)`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(java.util.Date)++[`dateDiff(OffsetDateTime)`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`dateDiff(Traversal)`]
+ [llms-summary="With dedup()-step (filter), repeatedly seen objects are removed from the traversal stream."]
[[dedup-step]]
=== Dedup Step
@@@ -1886,44 -1754,7 +1920,45 @@@ g.V(
* link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#drop()++[`drop()`]
+[[droplabel-step]]
+=== DropLabel Step
+
+The `dropLabel()`-step (*sideEffect*) removes one or more specific labels from an element and `dropLabels()`
+removes all of them. Like `addLabel()`, both require a `LabelCardinality` of `ZERO_OR_MORE` or `ONE_OR_MORE`.
+
+[gremlin-groovy]
+----
+conf = new BaseConfiguration()
+conf.setProperty("gremlin.tinkergraph.vertexLabelCardinality", "ZERO_OR_MORE")
+graph = TinkerGraph.open(conf)
+g = traversal().with(graph)
+v = g.addV('person').property('name','marko').addLabel('employee').addLabel('manager').next()
+g.V(v).labels()
+g.V(v).dropLabel('manager').labels() <1>
+g.V(v).dropLabel('manager').labels() <2>
+g.V(v).dropLabels().labels() <3>
+g.V(v).labels().count() <4>
+----
+
+<1> Removes the "manager" label.
+<2> Dropping a label that is not present has no effect.
+<3> Removes all remaining labels.
+<4> Confirms zero labels remain.
+
+NOTE: With `LabelCardinality.ONE_OR_MORE`, `dropLabels()` always throws and `dropLabel()` throws if it would
+leave the element with zero labels.
+
+IMPORTANT: Do not confuse `dropLabel()` with `labels().drop()`. The standalone `drop()` step either drops an
+`Element` from the `Graph`, or a `Property` from it's `Element`. Since a label is simply a `String` object,
+the `drop()` step cannot operate on it.
+
+*Additional References*
+
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dropLabel(java.lang.String,java.lang.String...)++[`dropLabel(String, String...)`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dropLabel(org.apache.tinkerpop.gremlin.process.traversal.Traversal,org.apache.tinkerpop.gremlin.process.traversal.Traversal...)++[`dropLabel(Traversal, Traversal...)`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dropLabels()++[`dropLabels()`]
+
+ [llms-summary="The E()-step is meant to read edges from the graph and is usually used to start a GraphTraversal, but can also be used mid-traversal."]
[[e-step]]
=== E Step
@@@ -1944,9 -1773,9 +1979,10 @@@ g.inject(1).coalesce(E().hasLabel("know
*Additional References*
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#E(java.lang.Object...)++[`E(Object...)`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#E(java.lang.Object...)++[`E(Object...)`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#E(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`E(Traversal)`]
+ [llms-summary="The element() step is a no-argument step that traverses from a Property to the Element that owns it."]
[[element-step]]
=== Element Step
@@@ -2129,8 -1928,9 +2170,9 @@@ information
*Additional References*
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#filter(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`filter(Traversal)`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#filter(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`map(Traversal)`]
+ [llms-summary="The flatMap() step maps the traverser from the current object to an Iterator of objects for the next step in the process."]
[[flatmap-step]]
=== FlatMap Step
@@@ -2152,8 -1952,9 +2194,9 @@@ gremlin> g.withSack(1.0f).V(1).barrier(
*Additional References*
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#flatMap(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`flatMap(Traversal)`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#flatMap(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`map(Traversal)`]
+ [llms-summary="The format()-step (map) builds a string from a template with placeholders filled by traverser values and properties."]
[[format-step]]
=== Format Step
@@@ -2437,8 -2191,10 +2485,9 @@@ link:++https://tinkerpop.apache.org/jav
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#hasValue(org.apache.tinkerpop.gremlin.process.traversal.P)++[`hasValue(P)`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/P.html++[`P`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/TextP.html++[`TextP`],
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/structure/T.html++[`T`],
-link:++https://tinkerpop.apache.org/docs/x.y.z/recipes/#has-traversal++[Recipes - Anti-pattern]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/structure/T.html++[`T`]
+ [llms-summary="The id()-step (map) takes an Element and extracts its identifier from it."]
[[id-step]]
=== Id Step
@@@ -2831,23 -2571,7 +2889,24 @@@ chosen non-deterministically
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#label()++[`label()`]
+[[labels-step]]
+=== Labels Step
+
+The `labels()`-step (*flatMap*) takes an `Element` and emits each of its labels as a separate traverser. For elements
+with a single label this behaves identically to `label()`. For multi-label elements, it emits one traverser per label.
+A vertex with no labels (possible only under `LabelCardinality.ZERO_OR_MORE`) emits nothing.
+
+[gremlin-groovy,theZoo]
+----
+g.V().labels()
+g.V().labels().count()
+----
+
+*Additional References*
+
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#labels()++[`labels()`]
+
+ [llms-summary="The length()-step (map) returns the length incoming string or list of string traverser."]
[[length-step]]
=== Length Step
@@@ -3000,28 -2717,25 +3064,29 @@@ The `map()` step maps the traverser fro
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#map(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`map(Traversal)`]
[[match-step]]
+ [llms-summary="The match() step (map) provides declarative, pattern-matching graph querying by combining traversal fragments bound to shared variables."]
=== Match Step
-The `match()`-step (*map*) provides a more link:http://en.wikipedia.org/wiki/Declarative_programming[declarative]
-form of graph querying based on the notion of link:http://en.wikipedia.org/wiki/Pattern_matching[pattern matching].
-With `match()`, the user provides a collection of "traversal fragments," called patterns, that have variables defined
-that must hold true throughout the duration of the `match()`. When a traverser is in `match()`, a registered
-`MatchAlgorithm` analyzes the current state of the traverser (i.e. its history based on its
-<<path-data-structure,path data>>), the runtime statistics of the traversal patterns, and returns a traversal-pattern
-that the traverser should try next. The default `MatchAlgorithm` provided is called `CountMatchAlgorithm` and it
-dynamically revises the pattern execution plan by sorting the patterns according to their filtering capabilities
-(i.e. largest set reduction patterns execute first). For very large graphs, where the developer is uncertain of the
-statistics of the graph (e.g. how many `knows`-edges vs. `worksFor`-edges exist in the graph), it is advantageous to
-use `match()`, as an optimal plan will be determined automatically. Furthermore, some queries are much easier to
-express via `match()` than with single-path traversals.
+Gremlin is a mostly imperative-style query language, but it also supports a means for defining a query declaratively,
+where users get a high degree of flexibility in deciding what parts of their query might be better written in one
+fashion or the other. Having this choice helps promote better query readability and query ergonomics and offers graph
+databases an opportunity to expose multi-language features and optimizations. This feature is provided by way of the
+`match()`-step.
- "Who created a project named 'lop' that was also created by someone who is 29 years old? Return the two creators."
+The `match()`-step (*map*) accepts a declarative query string, like link:https://www.iso.org/standard/76120.html[GQL],
+and executes it against the graph. TinkerPop ships an optional module, `gql-gremlin`, that provides the
+<<tinkergql,TinkerGQL>> dialect — a deliberate subset of ISO GQL `MATCH` syntax — which any graph system provider
+may adopt. Providers may also implement their own declarative query engine with a completely different language.
+*Whether `match()` is supported at all depends on the graph system being used.* Consult the documentation for your
+graph system to determine what query languages and syntax are accepted.
-image::match-step.png[width=500]
+Since `match()` is a provider-specific feature, a traversal that uses `match()` against a graph system that has not
+implemented support for it will throw an exception when the step is reached. The examples below are executed against
+TinkerGraph, which ships TinkerGQL support out of the box (see <<tinkergraph-gql>>), demonstrating how the step
+works in practice. What your graph system accepts may be entirely different.
+
+The step can be used in two ways. As a spawn step directly on a `GraphTraversalSource`, the pattern query is
+evaluated once and each result becomes a traverser:
[gremlin-groovy,modern]
----
@@@ -3343,9 -2941,9 +3408,10 @@@ Equivalent behaviour for `WHERE` and `R
*Additional References*
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#match(org.apache.tinkerpop.gremlin.process.traversal.Traversal...)++[`match(Traversal...)`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#match(java.lang.String)++[`match(String)`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#match(java.lang.String,java.util.Map)++[`match(String, Map)`]
+ [llms-summary="The math()-step (math) enables scientific calculator functionality within Gremlin."]
[[math-step]]
=== Math Step
@@@ -3621,8 -3223,9 +3691,9 @@@ link:++https://tinkerpop.apache.org/jav
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#mergeE(java.util.Map)++[`mergeE(Map)`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#mergeE(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`mergeE(Traversal)`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Merge.html++[`Merge`],
-link:++https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_mergee++[Semantics]
+link:++https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#merge-e-step++[`Semantics`]
+ [llms-summary="The mergeV() -step is used to add vertices and their properties to a graph in a \"create if not exist\" fashion."]
[[mergevertex-step]]
=== MergeVertex Step
@@@ -3854,8 -3425,9 +3925,9 @@@ link:++https://tinkerpop.apache.org/jav
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#mergeV(java.util.Map)++[`mergeV(Map)`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#mergeV(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`mergeV(Traversal)`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Merge.html++[`Merge`],
-link:++https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#_mergee++[Semantics]
+link:++https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#merge-v-step++[`Semantics`]
+ [llms-summary="The min()-step (map) operates on a stream of comparable objects and determines which is the first object according to its natural order in the stream."]
[[min-step]]
=== Min Step
@@@ -3915,7 -3487,9 +3988,8 @@@ g.V().values('age').fold().none(gt(25)
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#none(org.apache.tinkerpop.gremlin.process.traversal.P)++[`none(P)`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/P.html++[`P`]
-
[[not-step]]
+ [llms-summary="The not() step (filter) removes traversers for which the provided sub-traversal returns a result, negating a pattern."]
=== Not Step
The `not()`-step (*filter*) removes objects from the traversal stream when the traversal provided as an argument
@@@ -5128,8 -4720,9 +5227,9 @@@ see the <<general-steps, General Steps>
*Additional References*
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#sideEffect(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`sideEffect(Traversal)`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#sideEffect(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`map(Traversal)`]
+ [llms-summary="When it is important that a traverser not repeat its path through the graph, simplePath()-step should be used (filter)."]
[[simplepath-step]]
=== SimplePath Step
@@@ -5729,9 -5325,9 +5846,10 @@@ g.V().has('name', within('marko', 'vada
*Additional References*
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#V(java.lang.Object...)++[`V(Object...)`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#V(java.lang.Object...)++[`V(Object...)`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#V(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`V(Traversal)`]
+ [llms-summary="The value()-step (map) takes a Property and extracts the value from it."]
[[value-step]]
=== Value Step
@@@ -6230,46 -5790,7 +6355,47 @@@ By default, `GType` enumerations are re
g.V().values('age','name').is(P.typeOf('Integer'))
----
+[[canonical-gremlin-literal-types]]
+=== Canonical Gremlin Literal Types
+
+Canonical Gremlin represents typed values as text so that scripts and GLV requests can be expressed in the
+`gremlin-lang` language and parsed by the `gremlin-lang` script engine. The authoritative definition of this syntax is
+the link:https://github.com/apache/tinkerpop/blob/x.y.z/gremlin-language/src/main/antlr4/Gremlin.g4[Gremlin.g4 ANTLR grammar].
+This section summarizes the commonly used literal forms for convenience when reading canonical Gremlin or writing direct
+script requests.
+
+[width="100%",cols="2,3,6",options="header"]
+|=========================================================
+|Type |Canonical form |Expected input
+|null |`null` |The literal keyword `null`.
+|Boolean |`true`, `false` |The literal keywords `true` and `false`.
+|String |`"marko"`, `'marko'`, `"M"s` |A single-quoted or double-quoted string. The optional `s` suffix still produces a `String`.
+|Character |`"M"c`, `'M'c` |A single-quoted or double-quoted value that is one character.
+|Byte |`1B` |An integer with a `B` suffix and a value within the bounds of `Byte`.
+|Short |`1S` |An integer with an `S` suffix and a value within the bounds of `Short`.
+|Integer |`1`, `1I` |An integer within the bounds of `Integer`. The `I` suffix forces `Integer`.
+|Long |`1L` |An integer with an `L` suffix and a value within the bounds of `Long`.
+|BigInteger |`1N` |An integer with an `N` suffix.
+|Float |`1.0F` |A floating-point number with an `F` suffix and a value within the bounds of `Float`.
+|Double |`1.0`, `1.0D` |A floating-point number with an optional `D` suffix.
+|BigDecimal |`1.0M` |A floating-point number with an `M` suffix.
+|DateTime |`DateTime("2018-03-22T00:35:44Z")`, `DateTime()` |An ISO-8601 date or date-time string. `DateTime()` evaluates to the current time.
+|UUID |`UUID("f47af10b-58cc-4372-a567-0f02b2f3d479")`, `UUID()` |A UUID string in the textual form written as 8-4-4-4-12 hexadecimal digit groups. `UUID()` generates a random UUID.
+|Duration |`Duration(3600,0)`, `Duration(30,0,false)` |The first argument is non-negative seconds. The second is nanoseconds from `0` to `999999999`. The optional third argument is a boolean sign flag with `false` negating the duration.
+|Binary |`Binary("AQID")` |A Base64-encoded string.
+|Enum |`T.id`, `Cardinality.single`, `Direction.OUT` |A Gremlin enum token from `T`, `Cardinality`, `Direction`, `Merge`, `Pick`, `DT`, or `GType`.
+|List |`[1,"two",null]` |A comma-separated sequence of generic literals inside square brackets.
+|Set |`{1,"two"}` |A comma-separated sequence of generic literals inside braces.
+|Map |`[:]`, `["name":"marko", "age":29]` |An empty map is `[:]`. A populated map is a comma-separated sequence of `key:value` entries inside square brackets.
+|Provider Defined Type |`PDT("Point",["x":1,"y":2])`, `PDT("Uint32","42")` |The first argument is the provider-defined type name. The composite form expects a map literal with string keys. The primitive form expects an opaque string value.
+|=========================================================
+
+NOTE: Numeric values may be signed, and integer values may use decimal, hexadecimal (`0x`), or octal (`0`) notation.
+Underscores may appear between digits. Numeric type suffixes are accepted in either uppercase or lowercase form, though
+the examples above use uppercase suffixes. Special floating-point values are expressed as `NaN`, `Infinity`,
+`+Infinity`, or `-Infinity`.
+
+ [llms-summary="A note on maps in Gremlin, including differences in behavior between embedded and remote contexts."]
[[a-note-on-maps]]
== A Note on Maps
diff --cc docs/src/upgrade/release-3.2.x-incubating.asciidoc
index 18ef7d7448,820620712e..ab546bb583
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@@ -1456,9 -1459,10 +1458,10 @@@ See: link:https://issues.apache.org/jir
The method signatures of `get_g_VXlistXv1_v2_v3XX_name` and `get_g_VXlistX1_2_3XX_name` of `VertexTest` were changed
to take arguments for the `Traversal` to be constructed by extending classes.
+ [llms-summary="Upgrade notes specific to the TinkerPop 3.2.0 release: its breaking changes, new features, and changelog."]
== TinkerPop 3.2.0
-*Release Date: Release Date: April 8, 2016*
+*Release Date: April 8, 2016*
Please see the link:https://github.com/apache/tinkerpop/blob/3.2.0-incubating/CHANGELOG.asciidoc#tinkerpop-320-release-date-april-8-2016[changelog] for a complete list of all the modifications that are part of this release.
(tinkerpop) 02/03: Merge branch '3.7-dev' into 3.8-dev
Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit ceb0404b88f000be7232cd6f8096d67162b2f549
Merge: 1ac7e014a7 b75c29d797
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Wed Jul 29 15:08:51 2026 -0400
Merge branch '3.7-dev' into 3.8-dev
bin/process-docs.sh | 64 ++-
bin/publish-docs.sh | 32 ++
bin/validate-llms-txt.sh | 177 +++++++
docs/src/dev/developer/contributing.asciidoc | 4 +
.../dev/developer/development-environment.asciidoc | 64 ++-
docs/src/dev/developer/for-committers.asciidoc | 2 +
docs/src/dev/developer/index.asciidoc | 1 +
docs/src/dev/developer/meetings.asciidoc | 1 +
docs/src/dev/developer/release.asciidoc | 1 +
docs/src/dev/future/index.asciidoc | 1 +
docs/src/dev/io/graphson.asciidoc | 6 +
docs/src/dev/io/index.asciidoc | 1 +
docs/src/dev/provider/gremlin-semantics.asciidoc | 33 ++
docs/src/dev/provider/index.asciidoc | 6 +
docs/src/docinfo-footer.html | 19 +
docs/src/recipes/between-vertices.asciidoc | 1 +
docs/src/recipes/centrality.asciidoc | 1 +
docs/src/recipes/collections.asciidoc | 1 +
docs/src/recipes/connected-components.asciidoc | 1 +
docs/src/recipes/cycle-detection.asciidoc | 1 +
docs/src/recipes/duplicate-edge.asciidoc | 1 +
docs/src/recipes/duplicate-vertex.asciidoc | 1 +
docs/src/recipes/edge-move.asciidoc | 1 +
docs/src/recipes/element-existence.asciidoc | 1 +
docs/src/recipes/if-then-based-grouping.asciidoc | 1 +
docs/src/recipes/index.asciidoc | 3 +
docs/src/recipes/looping.asciidoc | 1 +
docs/src/recipes/olap-spark-yarn.asciidoc | 1 +
.../recipes/operating-on-dropped-elements.asciidoc | 1 +
docs/src/recipes/pagination.asciidoc | 1 +
docs/src/recipes/recommendation.asciidoc | 1 +
docs/src/recipes/shortest-path.asciidoc | 1 +
docs/src/recipes/traversal-induced-values.asciidoc | 1 +
docs/src/recipes/tree.asciidoc | 1 +
docs/src/reference/compilers.asciidoc | 1 +
docs/src/reference/gremlin-applications.asciidoc | 6 +
docs/src/reference/gremlin-variants.asciidoc | 7 +
.../implementations-hadoop-start.asciidoc | 1 +
docs/src/reference/implementations-intro.asciidoc | 1 +
docs/src/reference/intro.asciidoc | 1 +
docs/src/reference/preface.asciidoc | 1 +
docs/src/reference/the-graph.asciidoc | 1 +
docs/src/reference/the-graphcomputer.asciidoc | 1 +
docs/src/reference/the-traversal.asciidoc | 130 +++++
docs/src/tutorials/getting-started/index.asciidoc | 1 +
.../gremlin-language-variants/index.asciidoc | 3 +
docs/src/tutorials/gremlins-anatomy/index.asciidoc | 1 +
.../tutorials/the-gremlin-console/index.asciidoc | 1 +
docs/src/upgrade/index.asciidoc | 1 +
docs/src/upgrade/release-3.0.x-incubating.asciidoc | 1 +
docs/src/upgrade/release-3.1.x-incubating.asciidoc | 1 +
docs/src/upgrade/release-3.2.x-incubating.asciidoc | 3 +
docs/src/upgrade/release-3.3.x.asciidoc | 2 +
docs/src/upgrade/release-3.4.x.asciidoc | 2 +
docs/src/upgrade/release-3.5.x.asciidoc | 3 +
docs/src/upgrade/release-3.6.x.asciidoc | 1 +
docs/src/upgrade/release-3.7.x.asciidoc | 2 +
docs/tinkeradoc-extension/README.md | 14 +
.../tinkeradoc/GremlinDocsConverterRegistry.java | 36 ++
.../tinkeradoc/GremlinExecutionCache.java | 94 ++++
.../tinkerpop/tinkeradoc/GremlinHighlighter.java | 117 +++++
.../tinkerpop/tinkeradoc/GremlinPostprocessor.java | 37 +-
.../tinkerpop/tinkeradoc/GremlinTreeprocessor.java | 213 +++++----
.../tinkerpop/tinkeradoc/HtmlTabRenderer.java | 67 +++
.../tinkerpop/tinkeradoc/LlmsTxtGenerator.java | 288 ++++++++++++
.../tinkerpop/tinkeradoc/MarkdownConverter.java | 501 ++++++++++++++++++++
.../tinkerpop/tinkeradoc/MarkdownSplitter.java | 521 +++++++++++++++++++++
.../tinkerpop/tinkeradoc/MarkdownTabRenderer.java | 103 ++++
.../apache/tinkerpop/tinkeradoc/NeutralTab.java | 84 ++++
.../tinkerpop/tinkeradoc/NeutralTabCodec.java | 221 +++++++++
...ciidoctor.jruby.converter.spi.ConverterRegistry | 1 +
.../tinkeradoc/DualBackendIntegrationTest.java | 118 +++++
.../tinkeradoc/GremlinExecutionCacheTest.java | 124 +++++
.../tinkeradoc/GremlinHighlighterTest.java | 72 +++
.../tinkerpop/tinkeradoc/HtmlTabRendererTest.java | 104 ++++
.../tinkerpop/tinkeradoc/LlmsTxtGeneratorTest.java | 137 ++++++
.../tinkeradoc/MarkdownConverterProbeTest.java | 241 ++++++++++
.../tinkerpop/tinkeradoc/MarkdownSplitterTest.java | 227 +++++++++
.../tinkeradoc/MarkdownTabRendererTest.java | 113 +++++
.../tinkerpop/tinkeradoc/NeutralTabCodecTest.java | 113 +++++
.../tinkeradoc/PostprocessorBackendTest.java | 79 ++++
pom.xml | 275 +++++++++++
82 files changed, 4385 insertions(+), 120 deletions(-)
diff --cc docs/src/dev/provider/gremlin-semantics.asciidoc
index 1fc85258a4,be010f1814..bced422437
--- a/docs/src/dev/provider/gremlin-semantics.asciidoc
+++ b/docs/src/dev/provider/gremlin-semantics.asciidoc
@@@ -509,84 -528,7 +511,85 @@@ fully demonstrative of Gremlin step sem
step is meant to behave. This section discusses the semantics for individual steps to help users and providers
understand implementation expectations.
+[[adde-step]]
+=== addE()
+
+*Description:* Adds an edge to the graph.
+
+*Syntax:* `addE(String edgeLabel)` | `addE(Traversal<?, String> edgeLabelTraversal)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|Y |Y |`from()`/`to()` |`any` |`Edge`
+|=========================================================
+
+*Arguments:*
+
+* `edgeLabel` - The label of the edge to add.
+* `edgeLabelTraversal` - A traversal that produces the label of the edge to add.
+
+*Modulation:*
+
+* `from()` - Specifies the source vertex for the edge.
+* `to()` - Specifies the target vertex for the edge.
+
+*Considerations:*
+
+The `addE()` step can be used as both a start step and a mid-traversal step. When used as a start step, both `from()`
+and `to()` must be specified. When used as a mid-traversal step, the current traverser becomes the source vertex and
+only `to()` needs to be specified.
+
+The gremlin-lang grammar only permits `Traversal` and `String` (alias for `__.select(String)`) arguments in `from()` and
+`to()`. The `Traversal` must either produce a `Vertex` which is attachable to the graph, or it must produce the id of an
+existing `Vertex` in the graph. `GraphTraversal` implementations in GLVs may optionally support `from(Vertex)` and
+`to(Vertex)` as syntactic sugar. If translating to gremlin-lang scripts, these sugared modulators must be converted to
+`from(__.V(vertex.id()))` or `from(__.constant(vertex.id()))` (and equivalents for `to()`).
+
+*Exceptions*
+
+* If the edge label is null, an `IllegalArgumentException` will be thrown.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java[source],
+link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java[source (start)],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#addedge-step[reference]
+
+[[addv-step]]
+=== addV()
+
+*Description:* Adds a vertex to the graph.
+
+*Syntax:* `addV()` | `addV(String vertexLabel)` | `addV(Traversal<?, String> vertexLabelTraversal)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|Y |Y |N |`any` |`Vertex`
+|=========================================================
+
+*Arguments:*
+
+* `vertexLabel` - The label of the vertex to add.
+* `vertexLabelTraversal` - A traversal that produces the label of the vertex to add.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+The `addV()` step can be used as both a start step and a mid-traversal step. If no label is provided, the default
+vertex label for the graph will be used.
+
+*Exceptions*
+
+* If the vertex label is null, an `IllegalArgumentException` will be thrown.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java[source],
+link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java[source (start)],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#addvertex-step[reference]
+
+ [llms-summary="The formal semantics of the all() step: filters array data from the Traversal Stream if all of the array's items match the supplied predicate."]
[[all-step]]
=== all()
@@@ -620,72 -562,7 +623,73 @@@ will be filtered out of the Traversal S
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#all-step[reference]
+[[aggregate-step]]
+=== aggregate()
+
+*Description:* Collects all objects in the traversal into a collection.
+
+*Syntax:* `aggregate(String sideEffectKey)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |`by()` |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `sideEffectKey` - The name of the side-effect key that will hold the aggregated objects.
+
+*Modulation:*
+
+* `by()` - Determines how to transform the object before aggregating. If not specified, the object itself is used.
+
+*Considerations:*
+
+The `aggregate()` step is a side-effect step that collects objects but passes the traverser to the next step unchanged.
+The aggregated objects can be accessed later using the `cap()` step.
+
+*Exceptions*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#aggregate-step[reference]
+
+[[and-step]]
+=== and()
+
+*Description:* Ensures that all provided traversals yield a result.
+
+*Syntax:* `and(Traversal<?, ?>... andTraversals)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `andTraversals` - One or more traversals that will be executed against the current object.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+The `and()` step is a filter step that allows the traverser to pass if all of the provided traversals yield a result.
+It follows the ternary boolean logic described in the <<gremlin-semantics-concepts,Ternary Boolean Logics>> section.
+
+*Exceptions*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AndStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#and-step[reference]
+
+ [llms-summary="The formal semantics of the any() step: filters array data from the Traversal Stream if any of the array's items match the supplied predicate."]
[[any-step]]
=== any()
@@@ -719,67 -596,7 +723,68 @@@ filtered out of the Traversal Stream
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#any-step[reference]
+[[as-step]]
+=== as()
+
+*Description:* Labels a step for later access by steps that make use of such labels.
+
+*Syntax:* `as(String stepLabel, String... stepLabels)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `stepLabel` - The label to assign to the step.
+* `stepLabels` - Additional labels to assign to the step.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+The `as()` step is not a real step, but a "step modulator" similar to `by()` and `option()`. It allows labeling a step
+for later access by steps like `select()` and `match()`. A step can have any number of labels associated with it, which
+is useful for referencing the same step multiple times in a future step.
+
+*Exceptions*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#as-step[reference]
+
+[[asBool-step]]
+=== asBool()
+
+*Description:* Parse the value of the incoming traverser as boolean.
+
+*Syntax:* `asBool()`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Number`/`String`/`Boolean` |`Boolean`
+|=========================================================
+
+*Arguments:*
+
+None
+
+Booleans are passed as is, numbers evaluate to `true` if non-zero, and `false` if zero or `NaN`. Strings only accept "true" or "false" (case-insensitive).
+
+*Exceptions*
+
+If the incoming traverser type is unsupported, a string other than "true" or "false", or `null`, then an `IllegalArgumentException` is thrown.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsBoolStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asBool-step[reference]
+
+ [llms-summary="The formal semantics of the asDate() step: parse the value of incoming traverser as date."]
[[asDate-step]]
=== asDate()
@@@ -793,238 -610,11 +798,239 @@@
|N |Y |N |`any` |`any`
|=========================================================
-*Arguments:*
+*Arguments:*
+
+None
+
+Incoming date remains unchanged.
+
+*Exceptions*
+
+* If the incoming traverser is a non-String/Number/Date value then an `IllegalArgumentException` will be thrown.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asDate-step[reference]
+
+[[asNumber-step]]
+=== asNumber()
+
+*Description:* converts the incoming traverser to the nearest parsable type if no argument is provided, or to the desired numerical type, based on the type token (`GType`) provided.
+
+*Syntax:* `asNumber()` | `asNumber(GType typeToken)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Number`/`String`/`Date` |`Number`
+|=========================================================
+
+*Arguments:*
+
+* `typeToken` - The enum `GType` to denote the desired type to parse/cast to.
+
+If no type token is provided, the incoming number remains unchanged. A `Date` input is converted to milliseconds since epoch. A `null` input passes through as `null`.
+
+*Exceptions*
+
+* If any overflow occurs during narrowing of types, then an `ArithmeticException` will be thrown.
+* If the incoming string cannot be parsed into a valid number format, then a `NumberFormatException` will be thrown.
+* If the incoming traverser is a non-String/Number/Date value then an `IllegalArgumentException` will be thrown.
+* If the supplied type token is not a number type, then an `IllegalArgumentException` will be thrown.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asNumber-step[reference]
+
++[llms-summary="The formal semantics of the asString() step: returns the value of incoming traverser as strings, or if Scope.local is specified, returns each element inside incoming list traverser as string."]
+[[asString-step]]
+=== asString()
+
+*Description:* Returns the value of incoming traverser as strings, or if `Scope.local` is specified, returns each element inside
+incoming list traverser as string.
+
+*Syntax:* `asString()` | `asString(Scope scope)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`any` |`String`/`List`
+|=========================================================
+
+*Arguments:*
+
+* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
+The `global` scope will operate on individual traverser, casting all (except `null`) to string. The `local` scope will behave like
+`global` for everything except lists, where it will cast individual non-`null` elements inside the list into string and return a
+list of string instead.
+
+*Exceptions*
+
+* If the incoming traverser is a `null` value then an `IllegalArgumentException` will be thrown.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringGlobalStep.java[source],
+link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringLocalStep.java[source (local)],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asString-step[reference]
+
+[[barrier-step]]
+=== barrier()
+
+*Description:* Turns the lazy traversal pipeline into a bulk-synchronous pipeline.
+
+*Syntax:* `barrier()` | `barrier(int maxBarrierSize)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `maxBarrierSize` - The maximum number of traversers that can be held in the barrier before being processed.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+The `barrier()` step is useful in the following situations:
+* When everything prior to `barrier()` needs to be executed before moving onto the steps after the `barrier()` (i.e., ordering).
+* When "stalling" the traversal may lead to a "bulking optimization" in traversals that repeatedly touch many of the
+same elements (i.e., optimizing).
+
+*Exceptions*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/NoOpBarrierStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#barrier-step[reference]
+
+[[both-step]]
+=== both()
+
+*Description:* Maps a vertex to its adjacent vertices given the edge labels.
+
+*Syntax:* `both(String... edgeLabels)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Vertex` |`Vertex`
+|=========================================================
+
+*Arguments:*
+
+* `edgeLabels` - The edge labels to traverse. If no labels are provided, all edges are traversed.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+The `both()` step is a vertex-centric step that traverses both incoming and outgoing edges from the current vertex to
+adjacent vertices. It is equivalent to the union of `in()` and `out()`.
+
+*Exceptions*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#vertex-steps[reference]
+
+[[bothe-step]]
+=== bothE()
+
+*Description:* Maps a vertex to its incident edges given the edge labels.
+
+*Syntax:* `bothE(String... edgeLabels)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Vertex` |`Edge`
+|=========================================================
+
+*Arguments:*
+
+* `edgeLabels` - The edge labels to traverse. If no labels are provided, all edges are traversed.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+The `bothE()` step is a vertex-centric step that traverses both incoming and outgoing edges from the current vertex. It
+is equivalent to the union of `inE()` and `outE()`.
+
+*Exceptions*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#vertex-steps[reference]
+
+[[bothv-step]]
+=== bothV()
+
+*Description:* Maps an edge to its incident vertices.
+
+*Syntax:* `bothV()`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Edge` |`Vertex`
+|=========================================================
+
+*Arguments:*
+
+None
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+The `bothV()` step is an edge-centric step that traverses to both the incoming and outgoing vertices of the current
+edge. It is equivalent to the union of `inV()` and `outV()`.
+
+*Exceptions*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeVertexStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#vertex-steps[reference]
+
+[[branch-step]]
+=== branch()
+
+*Description:* Splits the traverser to all the specified traversals.
+
+*Syntax:* `branch(Traversal<?, M> branchTraversal)` | `branch(Function<Traverser<E>, M> function)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |`option()` |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `branchTraversal` - The traversal to branch the traverser to.
+* `function` - The function to branch the traverser to.
+
+*Modulation:*
-None
+* `option()` - Specifies the branch options for the traverser.
-Incoming date remains unchanged.
+*Considerations:*
+
+The `branch()` step is a general step that splits the traverser to all the child traversals provided to it. It's the
+basis for more robust steps like `choose()` and `union()`. The branch step is typically used with the `option()` step
+to specify the branch options.
*Exceptions*
@@@ -1064,9 -651,11 +1070,10 @@@ provided key. If multiple keys are prov
None
-See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringGlobalStep.java[source],
-link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringLocalStep.java[source (local)],
-link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asString-step[reference]
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SideEffectCapStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#cap-step[reference]
+ [llms-summary="The formal semantics of the call() step: provides support for provider-specific service calls."]
[[call-step]]
=== call()
@@@ -1152,67 -741,7 +1159,68 @@@ link:https://github.com/apache/tinkerpo
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/service/ServiceRegistry.java[ServiceRegistry],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#call-step[reference]
+[[choose-step]]
+=== choose()
+
+*Description:* A branch step that routes the traverser to different paths based on a choice criterion.
+
+*Syntax:* `choose(Traversal|T choice)` | `choose(Traversal|P choice, Traversal trueChoice)` |`choose(Traversal|P choice, Traversal trueChoice, Traversal falseChoice)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |Y |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `choice` - A `Traversal`, or `T` that produces a value used to determine which option to take. In the `if-then` forms, this value may be a `P` to determine `true` or `false`.
+* `trueChoice` - The traversal to take if the predicate traversal returns a value (has a next element).
+* `falseChoice` - The traversal to take if the predicate traversal returns no value (has no next element).
+
+*Modulation:*
+
+* `option(pickToken, traversalOption)` - Adds a traversal option to the `choose` step. The `pickToken` is matched
+against the result of the choice traversal. The `pickToken` may be a literal value, a predicate `P` or a `Pick` enum
+value. `Traversal` is not allowed as a `pickToken` here and will lead to `IllegalArgumentException`. If a match is
+found, the traverser is routed to the corresponding `traversalOption`.
+
+*Considerations:*
+
+The `choose()` step is a branch step that routes the traverser to different paths based on a choice criterion. There are
+two main forms of the `choose()` step:
+
+1. *if-then form*: `choose(predicate, trueChoice, falseChoice)` - If the predicate traversal or `P` returns a value
+(has a next element), the traverser is routed to the trueChoice traversal. Otherwise, it is routed to the falseChoice
+traversal. If the predicate is unproductive or if the falseChoice is not specified, then the traverser passes through.
+
+2. *switch form*: `choose(choice).option(pickValue, resultTraversal)` - The choice which may be a `Traversal` or
+`T` produces a value that is matched against the pickValue of each option. If a match is found, the traverser is routed
+to the corresponding resultTraversal and no further matches are attempted. If no match is found then the traverser
+passes through by default or can be matched on `Pick.none`. If the choiceTraversal is unproductive, then the traverser
+passes through by default or can be matched on `Pick.unproductive`.
+
+`choose` does not allow more than one traversal to be assigned to a single `Pick`. The first `Pick` assigned via
+`option` is the one that will be used, similar to how the first pickValue match that is found is used.
+
+The `choose()` step ensures that only one option is selected for each traverser, unlike other branch steps like
+`union()` that can route a traverser to multiple paths. As it is like `union()`, note that each `option` stream will
+behave like one:
+
+[gremlin-groovy,modern]
+----
+g.V().union(__.has("name", "vadas").values('age').fold(), __.has('name',neq('vadas')).values('name').fold())
+g.V().choose(__.has("name", "vadas"), __.values('age').fold(), __.values('name').fold())
+----
+
+*Exceptions*
+
+* `IllegalArgumentException` - If `Pick.any` is used as an option token, as only one option per traverser is allowed.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#choose-step[reference]
+
+ [llms-summary="The formal semantics of the combine() step: its exact expected behavior when merging an incoming list with a supplied list argument."]
[[combine-step]]
=== combine()
@@@ -1249,39 -778,7 +1257,40 @@@ See: link:https://github.com/apache/tin
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#combine-step[reference],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#merge-step[merge() reference]
+[[coin-step]]
+=== coin()
+
+*Description:* Filters traversers from the Traversal Stream based on a biased coin toss.
+
+*Syntax:* `coin(double probability)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `probability` - The probability (between 0.0 and 1.0) that the traverser will pass through the filter.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+Each traverser is subject to a random filter based on the provided probability. A probability of 0.0 means no
+traversers pass through, while a probability of 1.0 means all traversers pass through.
+
+*Exceptions*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#coin-step[reference]
+
+ [llms-summary="The formal semantics of the concat() step: concatenates the incoming String traverser with the input String arguments, and return the joined String."]
[[concat-step]]
=== concat()
@@@ -1557,86 -1061,7 +1573,87 @@@ Non
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/FormatStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#format-step[reference]
+[[group-step]]
+=== group()
+
+*Description:* Groups objects in the traversal stream by a key and applies a reducing operation to the grouped values.
+
+*Syntax:* `group()` | `group(String sideEffectKey)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |`by()` |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `sideEffectKey` - The name of the side-effect key that will hold the aggregated grouping. When provided, the step
+operates as a side-effect barrier step and passes the traverser to the next step unchanged. If `sideEffectKey` is
+omitted, the step operates as a reducing barrier step, and a single traverser containing the computed map is passed to
+the next step.
+
+*Modulation:*
+
+* `by()` - The first `by()` determines the key for grouping. The second `by()` determines the value to be reduced for
+each group. If no key `by()` is provided, the object itself is used as the key. If no value `by()` is provided, the
+objects are collected into a list.
+
+*Considerations:*
+
+The `group()` step can be used as both a reducing barrier step and a side-effect step. As a reducing barrier step (no
+side-effect key), it returns a `Map<Object, Object>` where keys are the grouping criteria and values are the reduced
+results. As a side-effect step, it stores the grouping in a side-effect and passes the traverser to the next step
+unchanged. In both forms, this step is a barrier and must fully iterate the traversal before returning any results.
+
+*Exceptions*
+
+* If more than 2 `by()` modulators are provided, an `IllegalStateException` will be thrown.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java[source],
+link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java[source (sideEffect)],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#group-step[reference]
+
+[[groupcount-step]]
+=== groupCount()
+
+*Description:* Counts the number of times a particular object has been part of a traversal, returning a `Map` where the
+object is the key and the value is the count.
+
+*Syntax:* `groupCount()` | `groupCount(String sideEffectKey)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |`by()` |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `sideEffectKey` - The name of the side-effect key that will hold the aggregated grouping. When provided, the step
+operates as a side-effect step and passes the traverser to the next step unchanged.
+
+*Modulation:*
+
+* `by()` - Determines how to transform the object before counting. If not specified, the object itself is used as the
+key.
+
+*Considerations:*
+
+The `groupCount()` step can be used as both a map step and a side-effect step. As a map step, it returns a
+`Map<Object, Long>` with the counted objects as keys and their counts as values. As a side-effect step, it stores the
+counts in a side-effect and passes the traverser to the next step unchanged. Note that both the map and side-effect
+forms of this step are barriers that must fully iterate the traversal before returning any results.
+
+*Exceptions*
+
+* If multiple `by()` modulators are provided, an `IllegalStateException` will be thrown.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupCountStep.java[source],
+link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountSideEffectStep.java[source (sideEffect)],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#groupcount-step[reference]
+
+ [llms-summary="The formal semantics of the length() step: returns the length of the incoming string or list, if Scope.local is specified, returns the length of each string elements inside incoming list traverser."]
[[length-step]]
=== length()
@@@ -1667,36 -1092,7 +1684,37 @@@ See: link:https://github.com/apache/tin
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LengthLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#length-step[reference]
+[[local-step]]
+=== local()
+
+*Description:* Executes the provided traversal in an object-local manner.
+
+*Syntax:* `local(Traversal localTraversal)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `localTraversal` - The traversal that processes each single-object traverser individually.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+The `local()` step enforces object-local execution. As a branching step with local children, it implements strict lazy
+evaluation by passing a single traverser at a time to the local traversal (bulk of exactly one, if bulking is supported)
+and resetting the traversal to clean state between executions.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LocalStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#local-step[reference]
+
+ [llms-summary="The formal semantics of the intersect() step: adds the intersection to the Traversal Stream."]
[[intersect-step]]
=== intersect()
@@@ -1978,40 -1379,7 +2001,41 @@@ resolve to a `Map`
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#mergev-step[reference]
+[[none-step]]
+=== none()
+
+*Description:* Filters array data from the traversal stream if none of the array's items match the supplied predicate.
+
+*Syntax:* `none(P predicate)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`List`/`array`/`Iterable`/`Iterator` |`List`/`array`/`Iterable`/`Iterator`
+|=========================================================
+
+*Arguments:*
+
+* `predicate` - The predicate used to test each value in the array data.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+Each value will be tested using the supplied predicate. Empty lists always pass through and null/non-list traversers
+will be filtered out of the traversal stream.
+
+*Exceptions*
+
+* A GremlinTypeErrorException will be thrown if one occurs and no other value evaluates to true.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#none-step[reference]
+
+
+ [llms-summary="The formal semantics of the product() step: adds the cartesian product to the Traversal Stream."]
[[product-step]]
=== product()
@@@ -2046,43 -1414,7 +2070,44 @@@ applies to list types which means that
See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#product-step[reference]
+[[project-step]]
+=== project()
+
+*Description:* Projects the current object in the stream into a `Map` that is keyed by the provided labels.
+
+*Syntax:* `project(String projectKey, String... otherProjectKeys)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |`by()` |`any` |`Map<String, Object>`
+|=========================================================
+
+*Arguments:*
+
+* `projectKey` - The first key to use in the resulting map.
+* `otherProjectKeys` - Additional keys to use in the resulting map.
+
+*Modulation:*
+
+* `by()` - Determines how to transform the current object for each key in the resulting map. The number of `by()`
+modulations should match the number of keys provided.
+
+*Considerations:*
+
+The `project()` step is similar to `select()` but instead of retrieving historic traverser state, it modulates the
+current state of the traverser. Each key in the resulting map corresponds to a `by()` modulation in the order they are
+provided. If a `by()` modulation doesn't produce a value for a particular key (not productive), that key will be omitted
+from the resulting `Map`.
+
+*Exceptions*
+
+* If duplicate keys are provided, an `IllegalArgumentException` will be thrown.
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#project-step[reference]
+
+ [llms-summary="The formal semantics of the repeat() step: iteratively applies a traversal (the \"loop body\") to each incoming traverser until a stopping condition is met."]
[[repeat-step]]
=== repeat()
@@@ -2280,40 -1613,7 +2309,41 @@@ See: link:https://github.com/apache/tin
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#split-step[reference]
+[[subgraph-step]]
+=== subgraph()
+
+*Description:* Extracts an edge-induced subgraph from the current graph based on the edges encountered during traversal.
+
+*Syntax:* `subgraph(String sideEffectKey)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |N |`Edge` |`Edge`
+|=========================================================
+
+*Arguments:*
+
+* `sideEffectKey` - The name of the side-effect key that will hold the extracted subgraph.
+
+*Modulation:*
+
+None
+
+*Considerations:*
+
+The `subgraph()` step is a side-effect step that extracts edges encountered during traversal and their incident vertices
+into a new subgraph. The step passes traversers through unchanged while building the subgraph as a side-effect. Subgraph
+step is a barrier and must fully iterate the traversal before returning any results.
+
+*Exceptions*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphStep.java[source],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#subgraph-step[reference]
+
+ [llms-summary="The formal semantics of the substring() step: its exact expected behavior extracting a portion of a string by index."]
[[substring-step]]
=== substring()
@@@ -2407,48 -1709,7 +2439,49 @@@ See: link:https://github.com/apache/tin
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ToUpperLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#toUpper-step[reference]
+[[tree-step]]
+=== tree()
+
+*Description:* Aggregates the paths of the traversal into a tree data structure.
+
+*Syntax:* `tree()` | `tree(String sideEffectKey)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |`by()` |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `sideEffectKey` - The name of the side-effect key that will hold the aggregated tree. When provided, the step
+operates as a side-effect step and passes the traverser to the next step unchanged. If omitted, the step acts as a
+reducing barrier step, and a single traverser containing the aggregated tree is passed to the next step.
+
+*Modulation:*
+
+* `by()` - Determines how to transform path objects before adding them to the tree. If not specified, the objects
+themselves are used as tree nodes. If multiple `by()` modulators are provided, they will be applied to each level of the
+tree according to a round robin. For example, if 2 `by()` modulators are present, the first `by()` will apply to the
+first, third, fifth... levels of the tree, and the second `by()` will apply to the second, fourth, sixth... levels of
+the tree. An unlimited number of `by()` modulators may be provided.
+
+*Considerations:*
+
+The `tree()` step can be used as both a map step and a side-effect step. As a map step, it returns a `Tree` data
+structure representing the hierarchical paths taken during traversal. As a side-effect step, it stores the tree in a
+side-effect and passes the traverser to the next step unchanged. The tree structure reflects the branching paths of the
+traversal, with each level representing a step in the path.
+
+*Exceptions*
+
+None
+
+See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java[source],
+link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java[source (sideEffect)],
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#tree-step[reference]
+
+ [llms-summary="The formal semantics of the trim() step: returns a string with leading and trailing whitespace removed."]
[[trim-step]]
=== trim()
diff --cc docs/src/reference/the-traversal.asciidoc
index 3980f119cb,01afa7cf3e..6b979c286d
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@@ -652,7 -668,9 +659,8 @@@ g.E().local(aggregate('x').by('weight')
*Additional References*
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#aggregate(java.lang.String)++[`aggregate(String)`],
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#aggregate(org.apache.tinkerpop.gremlin.process.traversal.Scope,java.lang.String)++[`aggregate(Scope,String)`]
+ [llms-summary="It is possible to filter list traversers using all()-step (filter)."]
[[all-step]]
=== All Step
@@@ -796,27 -818,7 +808,28 @@@ g.V().hasLabel('person').values('age').
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asString()++[`asString()`]
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asString(org.apache.tinkerpop.gremlin.process.traversal.Scope)++[`asString(Scope)`]
+[[asBool-step]]
+=== AsBool Step
+
+The `asBool()`-step (*map*) converts the incoming traverser to a boolean value. If the traverser is already a boolean value, it is passed as-is. Numbers evaluate to
+`true` if non-zero, and to `false` if zero or `NaN`. Strings are only accepted when
+equal to `"true"` or `"false"` (case-insensitive), otherwise an `IllegalArgumentException` is thrown.
+All other types (including `null`) will throw an `IllegalArgumentException`.
+
+[gremlin-groovy,modern]
+----
+g.inject(1).asBool() <1>
+g.inject("false").asBool() <2>
+----
+
+<1> Convert number to boolean
+<2> Convert string to boolean
+
+*Additional References*
+
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asBool()++[`asBool()`]
+
+ [llms-summary="The asDate()-step (map) converts string or numeric input to Date."]
[[asDate-step]]
=== AsDate Step
@@@ -844,42 -844,7 +857,43 @@@ g.inject(datetime("2023-08-24T00:00:00Z
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asDate()++[`asDate()`]
+[[asNumber-step]]
+=== AsNumber Step
+
+The `asNumber()`-step (*map*) converts the incoming traverser to the nearest parsable type if no argument is provided,
+or to the desired numerical type, based on the type token (`GType`) provided. If a type token entered isn't a numerical type, an `IllegalArgumentException` will be thrown.
+
+Numerical input will pass through unless a type is specified by the number token. `ArithmeticException` will be thrown
+for any overflow during narrowing of types.
+
+String inputs are parsed into numeric values, choosing the smallest type that can represent the value without loss of
+precision. A whole number is parsed as an `Integer`, widening to `Long` or `BigInteger` if it is too large to fit.
+A number with a decimal point is parsed as a `Float`, widening to `Double` or `BigDecimal` when higher precision is
+required. A `NumberFormatException` will be thrown if the string cannot be parsed into a valid number format.
+
+Date inputs are converted to milliseconds since epoch (January 1, 1970, 00:00:00 GMT).
+
+A `null` input passes through as `null`. All other input types will result in `IllegalArgumentException`.
+
+[gremlin-groovy,modern]
+----
+g.inject(1234).asNumber() <1>
+g.inject(1.76d).asNumber() <2>
+g.inject(1.76d).asNumber(GType.INT) <3>
+g.inject("2023-08-02T00:00:00Z").asDate().asNumber() <4>
+----
+
+<1> An int will be passed through.
+<2> A double will be passed through.
+<3> A double is converted into an int.
+<4> A date is converted into milliseconds since epoch.
+
+*Additional References*
+
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asNumber()++[`asNumber()`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#asNumber(org.apache.tinkerpop.gremlin.process.traversal.GType)++[`asNumber(GType)`]
+
+ [llms-summary="The barrier()-step (barrier) turns the lazy traversal pipeline into a bulk-synchronous pipeline."]
[[barrier-step]]
=== Barrier Step
@@@ -1552,9 -1436,9 +1582,10 @@@ NOTE: The `dateDiff(Date)` method is de
*Additional References*
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(java.util.Date)++[`dateDiff(Date)`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(java.time.OffsetDateTime)++[`dateDiff(OffsetDateTime)`],
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#dateDiff(org.apache.tinkerpop.gremlin.process.traversal.Traversal)++[`dateDiff(Traversal)`]
+ [llms-summary="With dedup()-step (filter), repeatedly seen objects are removed from the traversal stream."]
[[dedup-step]]
=== Dedup Step
@@@ -1654,32 -1539,7 +1686,33 @@@ g.V().values("name").fold().difference(
link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#difference(java.lang.Object)++[`difference(Object)`]
link:++https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#difference-step++[`Semantics`]
+[[discard-step]]
+=== Discard Step
+
+The `discard()`-step (*filter*) filters all objects from a traversal stream. It is helpful with <<branch-step>> types
+of steps where a particular branch of code should "throw away" traversers. In the following example, traversers that
+don't match are filtered out of the traversal stream.
+
+[gremlin-groovy,modern]
+----
+g.V().choose(T.label).
+ option("person", __.out("knows").values("name")).
+ option("bleep", __.out("created").values("name")).
+ option(none, discard())
+----
+
+It is also useful for traversals that are executed remotely where returning results is not useful and the traversal is
+only meant to generate side-effects. Choosing not to return results saves in serialization and network costs as the
+objects are filtered on the remote end and not returned to the client side. Typically, this step does not need to be
+used directly and is quietly used by the `iterate()` terminal step which appends `discard()` to the traversal before
+actually cycling through results.
+
+*Additional References*
+
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Traversal.html#discard()++[`discard()`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Traversal.html#iterate()++[`iterate()`]
+
+ [llms-summary="The disjunct()-step (map) calculates the disjunct set between the incoming list traverser and the provided list argument."]
[[disjunct-step]]
=== Disjunct Step
@@@ -3411,11 -3328,11 +3484,12 @@@ g.V().values('age').fold().none(gt(25)
*Additional References*
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Traversal.html#none()++[`none()`]
-link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/Traversal.html#iterate()++[`iterate()`]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#none(org.apache.tinkerpop.gremlin.process.traversal.P)++[`none(P)`],
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/org/apache/tinkerpop/gremlin/process/traversal/P.html++[`P`]
+
[[not-step]]
+ [llms-summary="The not() step (filter) removes traversers for which the provided sub-traversal returns a result, negating a pattern."]
=== Not Step
The `not()`-step (*filter*) removes objects from the traversal stream when the traversal provided as an argument
@@@ -5474,55 -5414,7 +5598,56 @@@ location. Please see the <<io-step,docu
link:++https://tinkerpop.apache.org/javadocs/x.y.z/full/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.html#write()++[`write()`]
+[[traversal-parameterization]]
+== Traversal Parameterization
+
+A subset of gremlin steps are able to accept parameterized arguments also known as GValues. GValues can be used to
+provide protection against gremlin-injection attacks in cases where untrusted and unsanitized inputs must be passed as
+step arguments. Additionally, use of GValues may offer performance benefits in certain environments by making use of
+some query caching capabilities. Note that the reference implementation of the gremlin language and `gremlin-server` do
+not have such a query caching mechanism, and thus will not see any performance improvements through parameterization. Users
+should consult the documentation of their specific graph system details of potential performance benefits via parameterization.
+
+NOTE: There are unique considerations regarding parameters when using `gremlin-groovy` scripts. Groovy allows for parameterization
+at arbitrary points in the query in addition to the subset of parameterizable steps documented here. Groovy is also bound by
+a comparatively slow script compilation, which makes parameterization essential for performant execution of `gremlin-groovy` scripts.
+
+[cols="1,1"]
+|===
+|Step | Parameterizable arguments
+
+|<<addedge-step,addE()>> | String edgeLabel
+|<<addvertex-step,addV()>> | String vertexLabel
+|<<vertex-steps,both()>> | String... edgeLabels
+|<<vertex-steps,bothE()>> | String... edgeLabels
+|<<call-step,call()>> | Map params
+|<<from-step,from()>> | Vertex fromVertex
+|<<has-step,has()>> | String label
+|<<has-step,hasId()>> | Object id, Object... ids
+|<<has-step,hasLabel()>> | String label, String... labels
+|<<has-step,hasValue()>> | Object value, Object... values
+|<<vertex-steps,in()>> | String... edgeLabels
+|<<vertex-steps,inE()>> | String... edgeLabels
+|<<is-step,is()>> | Object value
+|<<limit-step,limit()>> | Long limit
+|<<mergeedge-step,mergeE()>> | Map searchCreate
+|<<mergevertex-step,mergeV()>> | Map searchCreate
+|<<option-step,option()>> | Map m
+|<<vertex-steps,out()>> | String... edgeLabels
+|<<vertex-steps,outE()>> | String... edgeLabels
+|<<property-step,property()>> | Object value, Object... values
+|<<range-step,range()>> | Long low, Long high
+|<<skip-step,skip()>> | Long limit
+|<<tail-step,tail()>> | Long limit
+|<<to-step,to()>> | String... edgeLabels, Vertex toVertex
+|<<vertex-steps,toE()>> | String... edgeLabels
+|===
+
+*Additional References*
+
+<<gremlin-java-gvalue,Java>>, <<parameterized-scripts,Server>>
+
+ [llms-summary="A note on predicates used in Gremlin traversals, including standard and text predicates."]
[[a-note-on-predicates]]
== A Note on Predicates
@@@ -5602,69 -5496,7 +5727,70 @@@ g.V().as('a').both().both().as('b').cou
g.V().as('a').both().both().as('b').where('a',neq('b')).count()
----
+[[a-note-on-types]]
+== A Note on Types
+
+Gremlin steps typically operate over a handful of types that are mostly standard across graph systems. There are the
+common numeric types like `Integer`, `Long`, `Double`, general types like `String`, and `Boolean`, container types like
+`List`, `Set`, and `Map`, and structural types particular to graphs such as `Vertex`, `Edge`, and `Property`. During
+traversal execution, it's common to encounter mixed data types, especially when extracting values from multiple
+properties or when working with heterogeneous data that may have been stored inconsistently over time.
+
+Gremlin identifies these types in the `GType` enumeration, offering a clear presentation of the standard data types one
+might typically encounter with Gremlin. This enumeration is an important part of the Gremlin language in that it acts
+as the argument to the `typeOf()` predicate used for filtering values based on their runtime data type.
+
+[[gtype-enum]]
+=== GType Enums
+
+`GType` consists of the following enumerations:
+
+* **Numeric types**: `INT`, `LONG`, `DOUBLE`, `FLOAT`, `BYTE`, `SHORT`, `BIGDECIMAL`, `BIGINT`
+* **General types**: `STRING`, `BOOLEAN`, `CHAR`, `UUID`, `BINARY`
+* **Collection types**: `LIST`, `SET`, `MAP`
+* **Graph types**: `VERTEX`, `EDGE`, `PROPERTY`, `VPROPERTY`, `PATH`, `TREE`, `GRAPH`
+* **Temporal types**: `DATETIME`, `DURATION`
+* **Special types**: `NULL`, `NUMBER` (supertype for all numeric types)
+
+As mentioned, the `typeOf()` predicate becomes particularly useful when dealing with mixed data scenarios. For example,
+you would like to only return the integer values of a set of properties for further processing:
+
+[gremlin-groovy,modern]
+----
+g.V().values('age','name').is(P.typeOf(GType.INT)).asNumber(GType.SHORT)
+----
+
+The `NUMBER` type allows for broader type-based filtering without needing to specify each individual numeric type:
+
+[gremlin-groovy,modern]
+----
+g.union(V(), E()).values().is(P.typeOf(GType.NUMBER))
+----
+
+Type filtering is also valuable when working with traversals that return mixed graph elements. For example, when a
+traversal might return both vertices and edges, you can add filter or condition based on the elements of interest:
+
+[gremlin-groovy,modern]
+----
+g.V().outE().inV().path().unfold().is(P.typeOf(GType.EDGE))
+g.V().outE().inV().path().unfold().choose(typeOf(VERTEX), values('name'), values('weight'))
+----
+
+[[global-type-cache]]
+=== GlobalTypeCache
+
+The `GlobalTypeCache` stores custom types registered by database providers as string-to-class mappings. These registered
+type names can then be used with `P.typeOf()` for type filtering in the traversal. Consult your provider's documentation
+for the correct type names when using provider-specific types.
+
+By default, `GType` enumerations are registered using their simple class names and can be used as shown below.
+
+[gremlin-groovy,modern]
+----
+g.V().values('age','name').is(P.typeOf('Integer'))
+----
+
+ [llms-summary="A note on maps in Gremlin, including differences in behavior between embedded and remote contexts."]
[[a-note-on-maps]]
== A Note on Maps