Skip to content

docs(sdk-java): bridge-ref parity for the inbound value_type annotation (#4087) - #4153

Merged
antoniosarosi merged 2 commits into
canaryfrom
antoniosarosi/java-value-type-parity
Aug 4, 2026
Merged

docs(sdk-java): bridge-ref parity for the inbound value_type annotation (#4087)#4153
antoniosarosi merged 2 commits into
canaryfrom
antoniosarosi/java-value-type-parity

Conversation

@antoniosarosi

@antoniosarosi antoniosarosi commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Parity investigation of the Java bridge against the new inbound value_type ABI annotation introduced in ceae8ea (#4087). Finding: #4087 already implemented the Java encoder/decoder support and the empty-list arm-fidelity test contract end-to-end — the one gap it left was the Java bridge-ref docs, which still describe the pre-migration wire shape. This PR is that docs parity fix. No runtime/codegen change was warranted.

What #4087 already did (verified, no change needed)

  • Inbound annotation. Java threads the declared union as a contextual type and emits value_type for the selected arm exactly in the ambiguity cases: BamlTypedValue(value, descriptor) for top-level args (emit.rs), parallel fieldDescs[] for class fields, item/value types for containers (ProtoWriter.encodeInboundValue). Covers empty-container arms, overlapping arms, and literal-vs-primitive. Java registers the Reject ambiguity policy (a typed producer), so it annotates rather than leaning on Python's dynamic SelectDefault.
  • Parity with Python. Python sets value_type only for class identity and media kind; Java matches both (now on value_type.class_ty / value_type.media.kind) and additionally annotates selected union arms — the extra information the sparse channel exists to carry for a typed producer.
  • Outbound. ProtoReader honors the new canonical selected_option_index (field 8), falling back to structural armMatchesValue only when absent.
  • Empty-list contract. TestUnions.test_round_trip_str_or_int_list already asserts full arm fidelity (empty via Arm0 stays Arm0, via Arm1 stays Arm1).

Docs brought back to truth

  • ref-java-inbound-encoding.md: add value_type = 1 to the InboundValue proto; new "The value_type annotation" section (how Java threads the contextual union); class identity / generic args now on value_type.class_ty, media kind on value_type.media.kind; union-arm + empty-container rows/notes; typed-producer-vs-dynamic deviation flag.
  • ref-java-outbound-decoding.md: union-variant decoding documents the selected_option_index-first resolution.

Test plan (full battery, cold builds)

  • bridge_ctypes value_decode: 18 passed
  • bex_engine conversion (union arm selection): 71 passed
  • sdkgen_java: 92 passed; cargo clippy -p sdkgen_java: clean
  • baml_bridge gradle test jar: BUILD SUCCESSFUL
  • cargo nextest run -p sdk_test_java: 10 passed, 1 skipped — all four fixture suites (docstrings_etc, function_calls, llm_functions, type_shapes), each javac + junit

Docs-only change; no fixture/test counts changed.

Summary by CodeRabbit

  • Documentation
    • Updated Java inbound encoding guidance to match the latest wire/proto behavior, including node-level value_type, class identity and reified generic type args, and improved union/empty-container annotation rules.
    • Revised Java outbound union decoding guidance to use canonical selected_option_index when available, with clear structural fallback, null handling, and error behavior.
    • Adjusted Rust inbound decode mapping descriptions and updated related examples/test references to reflect the new contracts.

@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
beps Ready Ready Preview, Comment Jul 23, 2026 7:37pm
promptfiddle Ready Ready Preview, Comment Jul 23, 2026 7:37pm
promptfiddle2 Ready Ready Preview, Comment Jul 23, 2026 7:37pm

Request Review

@github-actions

Copy link
Copy Markdown

⏭️ Performance benchmarks were skipped

Perf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to canary/main.

To run them on this PR, do any of the following, then push a commit (or re-run CI):

  • Add RUN_CODSPEED=1 to the PR description, or
  • Include run-perf or /perf in the PR title or any commit message.

…on (#4087)

#4087 migrated the Java bridge to the node-level InboundValue.value_type
sparse annotation (removing InboundClassValue.class_ty) and added the
outbound union selected_option_index, but left the Java bridge-ref docs
describing the pre-migration wire shape. Bring the two docs back to truth:

ref-java-inbound-encoding.md
- add value_type = 1 to the InboundValue proto block; document reserved
  field 1 on InboundClassValue
- new "The value_type annotation" section: how Java (a Reject-policy typed
  producer) threads the contextual declared union — BamlTypedValue for
  top-level args, fieldDescs for class fields, item/value types for
  containers — and emits value_type for the three canonical cases (empty
  container arm, overlapping arm, literal-vs-primitive)
- class identity / generic type_args now on value_type.class_ty (not the
  class_value payload); media kind on value_type.media.kind
- union-arm and empty-container rows/notes updated for arm fidelity;
  deviation flag records typed-producer vs Python's dynamic SelectDefault

ref-java-outbound-decoding.md
- union-variant decoding: honors canonical selected_option_index (field 8)
  first, structural armMatchesValue only as fallback; deviation flag updated

Docs-only; verified against ProtoWriter/ProtoReader/TypeRegistry/emit.rs and
the engine (bridge_ctypes value_decode, bex_engine conversion). Full battery
green: sdkgen_java 92 + clippy, baml_bridge gradle test+jar, sdk_test_java
nextest 10/10 (+1 skip).
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 526a5791-2dcc-4896-a347-812580618eaf

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The Java bridge references now document node-level inbound type annotations, contextual generic reification, empty-container union fidelity, and Rust decoding mappings. Outbound union decoding documentation specifies canonical index-based arm selection with structural matching fallback.

Changes

Java bridge reference updates

Layer / File(s) Summary
Inbound encoding and type annotations
baml_language/sdks/agent-docs/bridge-ref/ref-java-inbound-encoding.md
Documents InboundValue.value_type for exact types, class identity, generic arguments, media kinds, contextual union arms, empty containers, and Rust inbound decoding.
Outbound union decoding rules
baml_language/sdks/agent-docs/bridge-ref/ref-java-outbound-decoding.md
Documents selected_option_index-first union decoding, structural fallback, null handling, and descriptor-path behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • BoundaryML/baml#4087: Covers related Java bridge wire-level type identity and canonical union selection changes.

Poem

I’m a rabbit with a bridge to mend,
Type notes hop where class fields end.
Union arms now choose their place,
Empty bowls retain their trace.
Indexes guide each decoding flight—
Docs now make the pathway bright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is specific and accurately reflects the docs update around Java inbound value_type annotation, which is a major part of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch antoniosarosi/java-value-type-parity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@baml_language/sdks/agent-docs/bridge-ref/ref-java-inbound-encoding.md`:
- Around line 200-212: Update the sparse value_type documentation around the
“value_type annotation” sections to match encodeInboundValue: when selectedArm
is true, contextualType is promoted to exactNodeType and the selected arm is
annotated eagerly, including unambiguous primitive types. Keep the three
canonical ambiguity cases as explanations of when the annotation is necessary,
rather than limiting emission to those cases, and apply the same wording
consistently in the referenced sections.
- Around line 584-593: The inbound wire-payload documentation should separate
class identity from enum identity: keep the class FQN and generic-argument
description scoped to InboundValue.value_type, then add a distinct clause
explaining that enum instances use the InboundEnumValue oneof payload with its
name and variant fields.
- Around line 294-307: Update the documentation paragraph describing non-generic
or unbound instances so it does not claim byte identity with pre-generics
encoding; state that the output is byte-identical to post-#4087 non-generic
encoding, or remove the byte-level claim. Keep the existing explanation of empty
type arguments and node-level value_type behavior unchanged.

In `@baml_language/sdks/agent-docs/bridge-ref/ref-java-outbound-decoding.md`:
- Around line 549-552: Update decodeUnionWithDesc to preserve the raw
selectedOptionIndex returned by extractUnionSelectedType when wrapping the
wire-selected union arm; avoid recomputing the arm via
arms.indexOf(selectedType), which collapses duplicate or equivalent types to the
first declaration. Keep structural armMatchesValue fallback behavior unchanged
when no wire index is present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b7a7135a-b8ad-4b0b-a783-956012e08493

📥 Commits

Reviewing files that changed from the base of the PR and between 8875658 and 14816da.

📒 Files selected for processing (2)
  • baml_language/sdks/agent-docs/bridge-ref/ref-java-inbound-encoding.md
  • baml_language/sdks/agent-docs/bridge-ref/ref-java-outbound-decoding.md

Comment thread baml_language/sdks/agent-docs/bridge-ref/ref-java-inbound-encoding.md Outdated
Comment thread baml_language/sdks/agent-docs/bridge-ref/ref-java-inbound-encoding.md Outdated
Comment thread baml_language/sdks/agent-docs/bridge-ref/ref-java-outbound-decoding.md Outdated
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

Binary size checks passed

7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
baml-cli Linux 🔒 26.8 MB 11.4 MB file 26.2 MB +622.1 KB (+2.4%) OK
packed-program Linux 🔒 17.4 MB 7.2 MB file 17.0 MB +353.2 KB (+2.1%) OK
baml-cli macOS 🔒 20.8 MB 9.9 MB file 20.3 MB +480.3 KB (+2.4%) OK
packed-program macOS 🔒 13.6 MB 6.3 MB file 13.2 MB +330.8 KB (+2.5%) OK
baml-cli Windows 🔒 22.4 MB 10.2 MB file 21.9 MB +525.3 KB (+2.4%) OK
packed-program Windows 🔒 14.5 MB 6.4 MB file 14.2 MB +299.0 KB (+2.1%) OK
bridge_wasm WASM 16.4 MB 🔒 4.5 MB gzip 4.4 MB +65.6 KB (+1.5%) OK

🔒 = the size this artifact is GATED on (ceiling + delta). Binaries gate on file size (installed binary); WASM gates on gzip (download size). The other size is shown for information only.


Generated by cargo size-gate · workflow run

Four corrections from CodeRabbit on #4153, each verified against the
encoder/decoder before applying:

1. Eager arm annotation (inbound). ProtoWriter sets
   exactNodeType = selectedArm ? contextualType : null (:229) and the tail
   (:349-368) writes value_type for EVERY representable selected-arm node,
   not only shape-ambiguous ones — an `int | string` Arm0(7L) still writes
   value_type: int. Reword the "value_type annotation" section and the union
   table row: annotation is eager within a selected-arm subtree; the three
   canonical cases explain WHY the channel exists, not a per-node gate. The
   sparseness is at the boundary (non-arm containers stay bare).

2. Byte-identical claim (inbound). writeClassType always writes
   value_type.class_ty.name (:402-411); ceae8ea relocated ALL class
   identity off InboundClassValue.class_ty, so a non-generic class's wire is
   NOT byte-identical to the pre-migration encoding. Scope the claim to "the
   generics-reification channel adds nothing" and drop the cross-migration
   byte-identical assertion (deviation + practical-consequences bullet).

3. Enum identity (inbound). Enum FQN + variant ride
   InboundEnumValue.name/value, not value_type. Split the practical-
   consequences clause that lumped enum FQNs into value_type.

4. Descriptor-path union decode (outbound). decodeUnionWithDesc resolves the
   arm by TYPE (arms.indexOf(selectedType), :1219), not the raw wire index.
   Clarify that this is unambiguous because canonical union members are
   structurally distinct (baml_type::normalize canonicalize_union
   sort+dedups, normalize.rs:1601) — so the string|string duplicate-arm
   scenario is unrepresentable, and value-resolution is robust to any
   wire/descriptor order difference.

Docs-only; no runtime/codegen change.
@antoniosarosi

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
baml_language/sdks/agent-docs/bridge-ref/ref-java-inbound-encoding.md (1)

372-374: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the empty-container arm example.

Arm1(int[]) is inconsistent with int[] | string[]: int[] is the first-declared arm, so this cannot demonstrate selecting a non-first arm. Use string[] | int[], or change it to Arm0(int[]) and remove the “instead of the first-declared arm” wording.

🛠️ Proposed fix
-- **Empty container arm** (`int[] | string[]`, empty `Arm1(int[])`): the list
+- **Empty container arm** (`string[] | int[]`, empty `Arm1(int[])`): the list
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@baml_language/sdks/agent-docs/bridge-ref/ref-java-inbound-encoding.md` around
lines 372 - 374, Correct the empty-container arm example so it demonstrates
selection of a non-first arm: change the union ordering to string[] | int[]
while retaining Arm1(int[]), or use Arm0(int[]) and remove the claim that it
differs from the first-declared arm. Keep the surrounding explanation consistent
with the chosen correction.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@baml_language/sdks/agent-docs/bridge-ref/ref-java-inbound-encoding.md`:
- Around line 372-374: Correct the empty-container arm example so it
demonstrates selection of a non-first arm: change the union ordering to string[]
| int[] while retaining Arm1(int[]), or use Arm0(int[]) and remove the claim
that it differs from the first-declared arm. Keep the surrounding explanation
consistent with the chosen correction.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 520ddd30-7084-438c-a309-f6eeff14cb85

📥 Commits

Reviewing files that changed from the base of the PR and between 14816da and f42dc92.

📒 Files selected for processing (2)
  • baml_language/sdks/agent-docs/bridge-ref/ref-java-inbound-encoding.md
  • baml_language/sdks/agent-docs/bridge-ref/ref-java-outbound-decoding.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • baml_language/sdks/agent-docs/bridge-ref/ref-java-outbound-decoding.md

@antoniosarosi
antoniosarosi added this pull request to the merge queue Aug 4, 2026
Merged via the queue into canary with commit 69bc86d Aug 4, 2026
70 checks passed
@antoniosarosi
antoniosarosi deleted the antoniosarosi/java-value-type-parity branch August 4, 2026 17:24
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.

1 participant