Skip to content

fix!: Make AgentGraph traversal topological - #199

Merged
mattrmc1 merged 5 commits into
mainfrom
mmccarthy/AIC-3044/agent-graph-traversal
Aug 12, 2026
Merged

fix!: Make AgentGraph traversal topological#199
mattrmc1 merged 5 commits into
mainfrom
mmccarthy/AIC-3044/agent-graph-traversal

Conversation

@mattrmc1

@mattrmc1 mattrmc1 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Makes AgentGraphDefinition traversal topological and gives each visitor a dependency-scoped
execution context
, aligning the traversal behavior across the LaunchDarkly AI SDKs.

Previously traverse / reverseTraverse were plain BFS over a single shared, accumulating context
map. That had two problems:

  1. Ordering: where branches of unequal length converge, the convergence node ran on first
    discovery — before all of its predecessors had run.
  2. Context leakage & mutation: every callback saw the results of all previously-visited nodes
    (including unrelated parallel branches), and results were written back into the caller's context
    map.

What changed

lib/sdk/server-aiAgentGraphDefinition.java only (no public API/signature changes):

  • traverse now visits a node only after all of its reachable predecessors have been visited
    (Kahn over in-degree; the root is always released first). On cycles, the unvisited node with the
    lowest remaining in-degree is chosen next, ties broken by discovery order.
  • reverseTraverse now visits a node only after all of its reachable descendants have been
    visited, so the root is visited last (Kahn over out-degree, root excluded from cycle-break
    selection). Pure cycles now visit every node instead of being a no-op.
  • Scoped context: each callback receives a fresh map = the initial context plus only that node's
    true dependency results (transitive ancestors forward / descendants reverse). Dependencies are
    accumulated before the node is marked visited in both directions, so a self-loop node never
    includes itself; unrelated branches are excluded and the caller's map is never mutated. Cross-node
    data flows only through callback return values.
  • Determinism: discovery order is the graph's BFS encounter order (root first, then declared edge
    order), used only for tie-breaks.
void traverse(BiFunction<AgentGraphNode, Map<String, Object>, Object> fn, Map<String, Object> ctx);

Behavior change (breaking)

Titled fix! because visit order and callback-context contents change for graphs with convergent
paths, cycles, or parallel branches. Simple linear graphs are unaffected. Cross-SDK parity with
JS/Python/.NET/Java.

Tests

  • A data-driven test over the canonical cross-SDK vectors G1G6 (+G2b) asserts exact visit
    order and exact context keys in both directions.
  • Convergence runs the shared node last; pure cycle visits all nodes (root last); caller context not
    mutated; unrelated branches excluded; a dedicated self-loop test confirms a node is not in its own
    context; deterministic across runs. Redundant per-vector order-only tests were dropped in favor of
    the data-driven vector test.

Notes

  • No manual CHANGELOG.md edit — release-please generates it from the conventional-commit title.
  • Graph tracking / wire parsing unchanged; this PR is scoped to traversal + context.
  • Minor follow-up (not required): the class-level Javadoc still says traversal is "BFS-based" — worth
    updating to "topological / dependency-order" so the docs match the new behavior.

Note

Overview
Replaces BFS traverse / reverseTraverse on AgentGraphDefinition with dependency-ordered walks (Kahn-style, cycle-safe, BFS discovery for tie-breaks). Convergence nodes run only after all predecessors (or descendants in reverse); pure cycles now visit every reachable node instead of effectively no-oping on reverse.

Breaking behavior: each visitor gets a fresh map—initial ctx plus only that node’s true dependency results (ancestors forward, descendants reverse). The caller’s ctx is not mutated with node outputs, and parallel-branch results no longer leak into unrelated callbacks. Self-loops exclude the node from its own context.

Tests add cross-SDK G1–G8 vectors for exact visit order and context keys, plus determinism, diamond graphs, and caller-context immutability checks.

Reviewed by Cursor Bugbot for commit 3c24de6. Bugbot is set up for automated code reviews on this repo. Configure here.

@mattrmc1
mattrmc1 marked this pull request as ready for review July 29, 2026 21:54
@mattrmc1
mattrmc1 requested a review from a team as a code owner July 29, 2026 21:54

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit da3503b. Configure here.

@tanderson-ld
tanderson-ld self-requested a review August 11, 2026 19:28
@mattrmc1
mattrmc1 merged commit a100712 into main Aug 12, 2026
24 checks passed
@mattrmc1
mattrmc1 deleted the mmccarthy/AIC-3044/agent-graph-traversal branch August 12, 2026 21:37
mattrmc1 added a commit that referenced this pull request Aug 13, 2026
## Summary

Wires `lib/sdk/server-ai` into the repo's release and publish plumbing.
Release-please already tracks the module
(`release-please-config.json` + `.release-please-manifest.json` at
`0.2.0`) and has cut `launchdarkly-java-server-sdk-ai-0.1.0`
and `-0.2.0` tags and GitHub Releases — but nothing was listening for
the baton afterward, so `.github/actions/full-release`
(Publish → Publish Docs) has never run for the module.

Consequences today:

- `com.launchdarkly:launchdarkly-java-server-sdk-ai` has **zero versions
on Maven Central**, despite the module README
  advertising the coordinate as published.
- `https://launchdarkly.github.io/java-core/lib/sdk/server-ai/` returns
**404**; `gh-pages` contains
`lib/sdk/server`, `lib/shared/*`, `lib/java-server-sdk-otel`, and
`lib/java-server-sdk-redis-store` but no `server-ai`.
- There was no manual escape hatch either — the module was missing from
both `workflow_dispatch` choice lists.

This is config-only. No build or source changes are needed:
`lib/sdk/server-ai/build.gradle` already applies
`maven-publish`, `signing`, and `nexusPublishing`, sets
`archivesBaseName = 'launchdarkly-java-server-sdk-ai'`, declares
full POM metadata, and produces `withJavadocJar()` / `withSourcesJar()`
(both excluding
`com.launchdarkly.sdk.server.ai.internal`).

## What changed

`.github/workflows/release-please.yml`:

- New job output `package-server-sdk-ai-released` from
`steps.release.outputs['lib/sdk/server-ai--release_created']`.
- New `release-server-sdk-ai` job, identical in shape to the existing
per-module release jobs, gated on that output and
calling `./.github/actions/full-release` with `workspace_path:
lib/sdk/server-ai`, `dry_run: false`, `prerelease: false`.

`.github/workflows/manual-publish.yml` and
`.github/workflows/manual-publish-docs.yml`:

- Added `lib/sdk/server-ai` to the `workspace_path` choice lists so the
module can be published — and, importantly, so its
  Javadoc can be pushed to `gh-pages` — on demand.

## Follow-up (not in this PR)

1. **Backfill the Javadoc site immediately** after merge: dispatch
**Publish Docs** with `workspace_path: lib/sdk/server-ai`,
`dry_run: false`. `publish-pages` writes to `output_path:
lib/sdk/server-ai`, and `gh-pages` docs are overwritten in place
rather than versioned, so this is safe to run from `main` and makes the
GitHub Pages URL work without publishing a jar.
2. **First Central release should be a fresh version, not a back-publish
of `0.2.0`.** `main` carries unreleased changes on
top of the `0.2.0` tag — including a breaking one (#199, `fix!: Make
AgentGraph traversal topological`) — while
`gradle.properties` still reads `version=0.2.0`. Merging this PR and
letting the open release-please PR cut the next
   version gets the artifact published from a matching tree.
3. **Docs links** become referenceable once released:
`https://launchdarkly.github.io/java-core/lib/sdk/server-ai/` (Javadoc,
the analogue of the .NET
   `launchdarkly.github.io/dotnet-core/pkgs/sdk/server-ai/` page) and

`https://central.sonatype.com/artifact/com.launchdarkly/launchdarkly-java-server-sdk-ai`
(package page, the analogue of
   the NuGet listing).

## Verification

- [ ] `release-please` workflow parses and the new job appears in the
run graph (skipped when no server-ai release is cut).
- [ ] **Publish Docs** dispatch offers `lib/sdk/server-ai` and, after
running, `gh-pages` contains
`lib/sdk/server-ai/index.html` and the Pages URL renders the
`LDAIClient` Javadoc.
- [ ] After the next release,
`https://repo1.maven.org/maven2/com/launchdarkly/launchdarkly-java-server-sdk-ai/maven-metadata.xml`
lists the version (allow ~30 min for Central sync) and a scratch Gradle
project resolves the coordinate.
- [ ] Published sources/javadoc jars exclude
`com.launchdarkly.sdk.server.ai.internal` — the build already enforces
this, but
it's worth confirming on the first artifacts ever produced for real.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> <sup>[Cursor Bugbot](https://cursor.com/bugbot) is generating a
summary for commit eab1c4d. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
mattrmc1 pushed a commit that referenced this pull request Aug 13, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.3.0](launchdarkly-java-server-sdk-ai-0.2.0...launchdarkly-java-server-sdk-ai-0.3.0)
(2026-08-13)


### ⚠ BREAKING CHANGES

* Make AgentGraph traversal topological
([#199](#199))

### Features

* **server-ai:** stamp model metadata on AI usage events
([#192](#192))
([58f3c25](58f3c25))


### Bug Fixes

* Make AgentGraph traversal topological
([#199](#199))
([a100712](a100712))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Overview**
> **Release Please** bumps **launchdarkly-java-server-sdk-ai** from
**0.2.0** to **0.3.0** across `.release-please-manifest.json`,
`gradle.properties`, and `AISdkInfo.VERSION`.
> 
> The new **0.3.0** section in `CHANGELOG.md` records what ships in this
tag: a **breaking** change to **topological AgentGraph traversal**
([#199](#199)), **model
metadata on AI usage events**
([#192](#192)), and the
related traversal fix. This PR does not include those implementation
diffs—only version and release notes.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
084f641. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants