Skip to content

Add trace-backed boundary value artifacts and history - #3844

Merged
rossirpaulo merged 24 commits into
canaryfrom
paulo/data-ingestion
Jun 27, 2026
Merged

rossirpaulo merged 24 commits into
canaryfrom
paulo/data-ingestion

Conversation

@rossirpaulo

@rossirpaulo rossirpaulo commented Jun 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR implements the staged trace-backed boundary value ingestion work through Phase 7:

  • establishes BoundaryId as the execution/history identity and threads boundary context through native, WASM, and playground paths
  • captures root values, logs, per-call outputs/errors, and explicit call inputs through TraceHeap snapshots instead of retaining live BEX heap state
  • persists boundary history as .bamlprof structure plus .bamlvalue value records, with replay/open/history support in native and warm-session WASM paths
  • keeps readValue(boundaryId, valueRef) as the single hydration path for live and replayed values
  • adds boundary-local SHA-256 blob storage for large value bodies while leaving small records inline
  • ensures process-local handles, host-owned objects, and opaque values are represented as safe omissions/descriptors rather than raw handle keys in durable artifacts
  • supports model-generated image values by copying MediaValue RustData into trace-owned media snapshots and encoding them as BamlValueMedia

Why

Boundary traces need durable, replayable value artifacts without holding onto mutable VM heap pointers, CFFI handle-table keys, JS/Python registry entries, or other process-local state. The new pipeline separates hot structural tracing from cold value ingestion: capture copies BAML-visible values into TraceHeap, value consumers encode artifact-safe bytes, .bamlvalue/blob storage owns the body data, and the UI hydrates lazily via readValue.

Validation

Automated checks run across the phase stack include:

  • cargo test --manifest-path baml_language/Cargo.toml -p bex_events ids
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_events run_store
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_events history
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_events log
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_events blob -- --nocapture
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_events value -- --nocapture
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_engine trace_heap -- --nocapture
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_engine value_capture
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_engine trace_value -- --nocapture
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_engine --test identity
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_engine --test prof_gate
  • cargo test --manifest-path baml_language/Cargo.toml -p bridge_ctypes artifact_safe -- --nocapture
  • cargo test --manifest-path baml_language/Cargo.toml -p bridge_ctypes handle_table -- --nocapture
  • cargo test --manifest-path baml_language/Cargo.toml -p bex_heap trace_owned -- --nocapture
  • cargo test --manifest-path baml_language/Cargo.toml -p bridge_cffi host_value -- --nocapture
  • cargo check --manifest-path baml_language/Cargo.toml -p baml_lsp_server
  • cargo check --manifest-path baml_language/Cargo.toml -p bridge_wasm --target wasm32-unknown-unknown
  • pnpm --filter @b/pkg-proto test
  • pnpm --filter @b/pkg-playground test
  • git diff --check

Manual verification included native playground runs for boundary identity, history replay, root values, logs, explicit input snapshots, and Phase 7 image/blob behavior. The final Phase 7 browser check generated an image through ai-gateway-images / google/imagen-4.0-fast-generate-001; the playground rendered image (image/png) and persisted the large generated body as a SHA-256 blob while keeping the .bamlvalue record small.

Summary by CodeRabbit

  • New Features
    • Added boundary-based addressing to the Playground WebSocket, including history browsing and ReadValue support.
    • Introduced boundary-local ID capabilities (current/new/capture) and expanded trace value/log capture surfaces.
  • Bug Fixes
    • Improved $id/identity tracking and error tracing with correct rethrow behavior.
    • Enhanced call/throw handling so runtime identity and captured outcomes stay consistent across execution paths.
  • Chores
    • Updated toolchain status output to include rustup-style “from …” annotations for clearer install/version information.

Replace the public RunStore RunId surface with host-created BoundaryId while preserving the existing baml_id_1_ runtime-id encoding. Thread BoundaryContext through native and WASM execution entry points so the root VM frame, RunStore boundary key, and boundary.id.current() agree while structural CallRef attachment remains available for profiling and call reconstruction.

Rename playground protocol, store, projection, and adapter fields from runId/RunId to boundaryId/BoundaryId. Add the boundary.id stdlib package resolver, keep baml.id aliases over the same runtime-id surface, update identity/profile tests, and record phase-1 validation plus handoff notes in TASK.
Implement the phase 2 live root value path for playground execution.

Add TraceHeap snapshots and bounded capture queues in bex_engine for root input, output, and thrown BAML values. Add value artifact framing and ValueRef metadata in bex_events, then project refs through RunResult, RunError, and root capturedValue payloads without storing bodies in RunStore.

Wire native and WASM playground hosts to drain captured values at terminal safe points, retain live value bodies in host-owned stores, and answer readValue requests with codec-tagged BamlOutboundValue bodies. Update the TypeScript protocol, RunStore client, value-body cache, projections, and execution UI so root input/result/error bodies hydrate lazily before rendering.

Add focused Rust and TypeScript coverage for value framing, root value refs, WebSocket value frames, readValue correlation, cache hydration, and projection rendering.
Add boundary-scoped native history storage under project .baml/history with exact-root profile routing and per-thread stack/value segments.

Extend .bamlvalue capture metadata and replay helpers so opened history can hydrate RunStore snapshots, lazy value refs, root outputs, errors, and diagnostics through the same paths as live runs.

Wire native LSP, WASM bridge, playground protocol, and execution-store clients for explicit listHistory/openHistory/readValue behavior, including warm-session retained-byte replay for WASM.
Route reserved $baml_log events through the TraceCaptureProducer with boundary and call identity so log bodies are captured through TraceHeap rather than direct playground transport.

Persist log bodies and aggregate capture-loss records in .bamlvalue artifacts, replay them into RunStore payloads and diagnostics, and hydrate log bodies through readValue for live and history views.

Update native and WASM drain paths plus playground protocol/projections/UI so identified logs attach under reconstructed call nodes with value refs, lazy hydration states, and focused attribution coverage for repeated nested calls.
Add function capture metadata and VM capture masks so output/error capture can resolve Auto at the host boundary while ordinary helpers remain disabled by default.

Queue bytecode, native, and sys-op call outputs/errors through the TraceHeap value producer, preserving root outcomes as canonical RunResult/RunError refs and recording thrown values once at their origin.

Persist and replay call output/error value refs through RunStore, .bamlvalue history, native LSP, and WASM drains, then surface hydrated call values in playground trace rows.

Cover repeated-call attribution, native call output capture, origin-only rethrow semantics, RunStore/history replay, and playground projection/rendering.
Implement the architecture-safe explicit capture surface for Phase 6. This adds boundary.id(), boundary.LocalId.capture(...), hidden $id call lowering, ID-aware bytecode call forms, and VM dispatch support for explicit local ids without changing ordinary call arity.

Thread call-entry input capture through the narrow VM hook owned by bex_engine, preserving TraceHeap and TraceCaptureProducer ownership. Bytecode and sys-op boundaries can now capture named input snapshots with single-use LocalId policy, while unsupported native builtins and opaque host closures reject explicit $id for this v1 boundary.

Persist call inputs through the existing value artifact path as CallInput records, RunStore/history payloads, readValue bodies, and playground UI trace call values. LLM functions now resolve Auto for inputs, output, and error while ordinary functions remain capture-disabled by default.

Add validation coverage for mutation-isolated input snapshots, LocalId single-use behavior, native builtin rejection, sys-op input capture, call-value projection, and native playground hydration ordering. Native playground now flushes profile events before root trace attachment and completion so captured inputs attach to their call rows deterministically.
Add boundary-local SHA-256 blob storage for large value bodies while keeping readValue as the single hydration path. Blob-backed .bamlvalue records now retain small metadata inline and resolve bodies through HistoryStore without changing public availability semantics.

Add artifact-safe value encoding guardrails so persisted artifacts preserve durable primitives, containers, media, prompt AST, and type values while converting host-owned or process-local values into safe omission descriptors instead of serializing live handles.

Teach trace-owned snapshots to recognize MediaValue stored as RustData, copy media content into TraceHeap-owned data, and encode generated image results as BamlValueMedia. This keeps model-generated images replayable and blob-backed in the native playground.

Cover the phase with focused blob, value, history, artifact-safe, handle-table, trace-owned, media trace, bridge host-value, proto, and playground tests.
@vercel

vercel Bot commented Jun 25, 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 Jun 27, 2026 3:30am
promptfiddle Ready Ready Preview, Comment Jun 27, 2026 3:30am
promptfiddle2 Ready Ready Preview, Comment Jun 27, 2026 3:30am

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.

@vercel
vercel Bot temporarily deployed to Preview – beps June 25, 2026 03:55 Inactive
@coderabbitai

coderabbitai Bot commented Jun 25, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

BoundaryId replaces runId across identity, run records, VM call execution, capture routing, history storage, and playground APIs. The compiler and bytecode layers also add runtime_id and rethrow handling, while toolchain output and release verification are updated.

Changes

BoundaryId, runtime_id, capture, history, and playground v2

Layer / File(s) Summary
Boundary identity and builtin wiring
baml_language/crates/baml_builtins2/baml_std/boundary/*, baml_language/crates/baml_builtins2/src/lib.rs, baml_language/crates/baml_compiler2_hir/{Cargo.toml,src/package.rs}, baml_language/crates/bex_events/src/ids.rs, baml_language/crates/bex_events/src/lib.rs
BoundaryId and RuntimeId::Boundary are introduced, the boundary builtin package is registered, and builtin/package dependency checks are updated around the new boundary root.
TIR, MIR, and bytecode runtime ids
baml_language/crates/baml_compiler2_tir/src/builder.rs, baml_language/crates/baml_compiler2_mir/src/{builder.rs,ir.rs,lower.rs,optimize.rs,pretty.rs}, baml_language/crates/baml_tests/projects/diagnostic_errors/runtime_id_misuse/runtime_id.baml, baml_language/crates/baml_compiler2_emit/src/{analysis.rs,emit.rs,lib.rs,stack_carry.rs}, baml_language/crates/bex_vm_types/src/bytecode.rs, baml_language/crates/bex_vm/{src/debug.rs,tests/load_type.rs,tests/method_class_type_args.rs}, baml_language/crates/baml_tests/src/engine.rs
$id is split from normal arguments, MIR terminators carry optional runtime_id fields and Rethrow, and compiler lowering, optimization, emission, stack simulation, and pretty printing propagate those operands.
VM boundary helpers and capture dispatch
baml_language/crates/bex_vm/{src/lib.rs,src/vm.rs,src/package_baml/*,src/package_boundary/*,tests/events.rs}
The VM adds boundary-local id helpers, runtime-id-aware dispatch, capture masks, and event source-location plumbing.
Engine trace capture and value queues
baml_language/crates/bex_engine/{Cargo.toml,src/function_call_context.rs,src/lib.rs,src/trace_heap.rs,src/trace_value_encode.rs,src/value_capture.rs,tests/{identity.rs,prof_gate.rs}}, baml_language/crates/bex_heap/src/accessor.rs
Boundary-scoped function call contexts, trace heap snapshots, and producer-side capture queues are added, with tests covering boundary ids, captured values, and rethrow and origin behavior.
Value file format and artifact-safe encoding
baml_language/crates/bex_events/{Cargo.toml,build.rs,src/value/*}, baml_language/crates/bridge_ctypes/src/{handle_table.rs,value_encode.rs}
The .bamlvalue schema, record model, readers, writers, blob artifacts, live cache, and artifact-safe bridge encoding are added.
Run store and history replay
baml_language/crates/bex_events/src/{lib.rs,run.rs,run_wire.rs,history/*,prof/*}
Run records move to BoundaryId and value refs, wire JSON emits boundary and value fields, and history writers and replay reconstruct runs from stored profile and value segments.
Playground protocol v2
baml_language/crates/baml_lsp_server/{Cargo.toml,src/playground_{env,io,runs,server,ws}.rs}
Playground WebSocket messages and server handlers switch to boundaryId addressing, add history and value reads, and thread capture-enabled boundary runs through the server.

Workspace wiring and release support

Layer / File(s) Summary
Workspace re-exports and pack-host features
baml_language/crates/{bex_project/src/lib.rs,baml_pack_host/Cargo.toml,bex_vm_types/src/lib.rs}
Project re-exports and pack-host feature wiring are adjusted for the new engine and host package layout.
Selector annotations and release verification
baml_language/crates/{baml/src/main.rs,baml_release/src/lib.rs}, .github/workflows/size-gate.reusable.yaml, baml_language/.cargo/size-gate.toml, baml_language/.ci/size-gate/*
Toolchain status output gains selector annotations, release downloads verify checksums before archive layout validation or binary extraction, and size-gate reporting and baselines are refreshed.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant PlaygroundServer
  participant BexEngine
  participant TraceCaptureProducer
  participant HistoryStore
  participant LiveValueStore
  Client->>PlaygroundServer: FunctionRun / TestRun
  PlaygroundServer->>BexEngine: call with BoundaryId
  BexEngine->>TraceCaptureProducer: capture inputs, logs, outputs
  BexEngine-->>PlaygroundServer: outcome and queued captures
  PlaygroundServer->>TraceCaptureProducer: drain captured values
  TraceCaptureProducer->>HistoryStore: append value or log bodies
  TraceCaptureProducer->>LiveValueStore: retain live value body
  Client->>PlaygroundServer: ReadValue(boundaryId, valueRef)
  PlaygroundServer->>LiveValueStore: get value body
  PlaygroundServer->>HistoryStore: read_value_result fallback
  PlaygroundServer-->>Client: ValueBody
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • BoundaryML/baml#3154: Both PRs modify the bex_engine call-context plumbing (notably baml_language/crates/bex_engine/src/function_call_context.rs and how call_function/LSP/playground paths construct/pass FunctionCallContext).
  • BoundaryML/baml#3316: The main PR’s MIR/VM throw–catch handling changes, including Rethrow and exception unwinding, are tightly coupled with the same exception-flow areas.
  • BoundaryML/baml#3740: Both PRs work on the same BoundaryId / $id identity surface across compiler, VM, engine, and tests.
  • BoundaryML/baml#3786: Both PRs migrate playground run handling toward the run-store and websocket boundary-addressing flow.

Suggested reviewers

  • antoniosarosi

Poem

I hopped by moonlit BoundaryId rows,
where tiny $id carrots glow.
I tucked live bytes in history hay,
and watched rethrows hop away.
Hop hop — the playground pings with glee 🐰

🚥 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 accurately summarizes the main change: trace-backed boundary value artifacts plus history support.
Docstring Coverage ✅ Passed Docstring coverage is 99.43% which is sufficient. The required threshold is 80.00%.
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 paulo/data-ingestion

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.

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 25, 2026 04:01 Inactive
@github-actions

github-actions Bot commented Jun 25, 2026 •

Copy link
Copy Markdown

Binary size checks passed

✅ 7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
✅ baml-cli Linux 🔒 21.5 MB 9.2 MB file 21.5 MB +12.0 KB (+0.1%) OK
✅ packed-program Linux 🔒 15.6 MB 6.6 MB file 15.6 MB +0 B (+0.0%) OK
✅ baml-cli macOS 🔒 16.5 MB 8.0 MB file 16.1 MB +447.2 KB (+2.8%) OK
✅ packed-program macOS 🔒 12.0 MB 5.7 MB file 12.0 MB +50.2 KB (+0.4%) OK
✅ baml-cli Windows 🔒 18.1 MB 8.2 MB file 18.1 MB +0 B (+0.0%) OK
✅ packed-program Windows 🔒 13.0 MB 5.8 MB file 13.0 MB +0 B (+0.0%) OK
✅ bridge_wasm WASM 14.3 MB 🔒 4.1 MB gzip 4.1 MB +3 B (+0.0%) 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

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 25, 2026 04:13 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 25, 2026 04:34 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 25, 2026 04:40 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 25, 2026 04:51 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 25, 2026 06:11 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 25, 2026 06:17 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 25, 2026 06:29 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 25, 2026 06:35 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 25, 2026 06:41 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 25, 2026 06:52 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 25, 2026 06:59 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 25, 2026 07:10 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 27, 2026 00:30 Inactive
@rossirpaulo
rossirpaulo marked this pull request as ready for review June 27, 2026 00:31
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 27, 2026 00:36 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 27, 2026 00:48 Inactive

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
baml_language/crates/bex_events/src/value/read.rs (1)

90-98: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Also reject stray body/blob on capture-loss records.

The capture-loss guard rejects metadata, log_event, and capture, but not body or blob. A malformed/corrupted .bamlvalue capture-loss record carrying a body or blob is accepted and those fields are silently dropped, unlike the strict lifecycle path above (Lines 71-83). Tighten for consistency.

🛡️ Proposed fix
     if let Some(loss) = record.capture_loss {
-        if record.metadata.is_some() || has_log_event || record.capture.is_some() {
+        if record.metadata.is_some()
+            || has_log_event
+            || record.capture.is_some()
+            || !record.body.is_empty()
+            || record.blob.is_some()
+        {
             return Err(io::Error::new(
                 io::ErrorKind::InvalidData,
                 "value record mixed capture loss metadata with body metadata",
             ));
         }
         return Ok(ValueFileRecord::CaptureLoss(loss.try_into()?));
     }
🤖 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/crates/bex_events/src/value/read.rs` around lines 90 - 98, The
capture-loss handling in read_value_record is too permissive because it rejects
metadata, log_event, and capture but still accepts stray body/blob fields, which
are then silently dropped. Tighten the guard in the if let Some(loss) =
record.capture branch to also reject any record where body or blob is present,
matching the stricter validation used in the normal lifecycle path and keeping
ValueFileRecord::CaptureLoss conversion only for clean capture-loss records.
🧹 Nitpick comments (1)
baml_language/crates/bex_events/src/history/router.rs (1)

77-83: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

record(id) is now an O(n) linear scan (regression from O(1)).

records is always sorted ascending by id (ids are assigned monotonically in ingest and only the oldest are drained from the front), so a binary search restores logarithmic lookup. This matters because routing claims records by id and the buffer can hold up to max_records (default 100_000), turning per-claim lookups into a potential O(n²) over a full buffer.

♻️ Use the sorted-by-id invariant
     #[must_use]
     pub fn record(&self, id: HistoryProfileRecordId) -> Option<&HistoryProfileRecord> {
-        self.records
-            .iter()
-            .find(|record| record.id == id)
-            .map(|record| &record.record)
+        self.records
+            .binary_search_by_key(&id, |record| record.id)
+            .ok()
+            .map(|index| &self.records[index].record)
     }
🤖 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/crates/bex_events/src/history/router.rs` around lines 77 - 83,
`HistoryRouter::record` currently does a linear scan over `records`, which
regresses lookup performance; update this method to use the existing
sorted-by-`id` invariant and a binary search instead of `iter().find(...)`.
Locate the fix in `record(id)` and keep the return type/behavior unchanged by
returning the matched `HistoryProfileRecord` when the search succeeds,
preserving the current `Option<&HistoryProfileRecord>` API.
🤖 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/crates/bex_events/src/value/live_cache.rs`:
- Around line 158-170: The read path in LiveCache::get leaves stale tombstones
in lru on every cache hit, so the deque can grow without bound during repeated
reads. Update LiveCache to periodically compact/rebuild lru from the live
entries in sequence order when it grows too large relative to entries, and apply
the same cleanup to evicted_order since LiveCache::insert removes from evicted
without trimming that deque. Use the existing LiveValueKey, next_sequence, and
evict_until_within_budget flow to place the fix without changing lookup
behavior.

---

Outside diff comments:
In `@baml_language/crates/bex_events/src/value/read.rs`:
- Around line 90-98: The capture-loss handling in read_value_record is too
permissive because it rejects metadata, log_event, and capture but still accepts
stray body/blob fields, which are then silently dropped. Tighten the guard in
the if let Some(loss) = record.capture branch to also reject any record where
body or blob is present, matching the stricter validation used in the normal
lifecycle path and keeping ValueFileRecord::CaptureLoss conversion only for
clean capture-loss records.

---

Nitpick comments:
In `@baml_language/crates/bex_events/src/history/router.rs`:
- Around line 77-83: `HistoryRouter::record` currently does a linear scan over
`records`, which regresses lookup performance; update this method to use the
existing sorted-by-`id` invariant and a binary search instead of
`iter().find(...)`. Locate the fix in `record(id)` and keep the return
type/behavior unchanged by returning the matched `HistoryProfileRecord` when the
search succeeds, preserving the current `Option<&HistoryProfileRecord>` API.
🪄 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

Run ID: 7e8711dd-c427-4040-8ec9-3ecf9668c3aa

📥 Commits

Reviewing files that changed from the base of the PR and between 07636ce and 11d20c1.

⛔ Files ignored due to path filters (1)
  • baml_language/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • baml_language/crates/baml/src/main.rs
  • baml_language/crates/baml_compiler2_hir/Cargo.toml
  • baml_language/crates/baml_compiler2_hir/src/package.rs
  • baml_language/crates/baml_compiler2_mir/src/pretty.rs
  • baml_language/crates/baml_lsp_server/src/playground_server.rs
  • baml_language/crates/baml_pack_host/Cargo.toml
  • baml_language/crates/baml_release/src/lib.rs
  • baml_language/crates/bex_engine/src/trace_heap.rs
  • baml_language/crates/bex_engine/src/trace_value_encode.rs
  • baml_language/crates/bex_engine/src/value_capture.rs
  • baml_language/crates/bex_engine/tests/prof_gate.rs
  • baml_language/crates/bex_events/src/history/boundary_writer.rs
  • baml_language/crates/bex_events/src/history/mod.rs
  • baml_language/crates/bex_events/src/history/router.rs
  • baml_language/crates/bex_events/src/value/artifact.rs
  • baml_language/crates/bex_events/src/value/encode.rs
  • baml_language/crates/bex_events/src/value/live_cache.rs
  • baml_language/crates/bex_events/src/value/mod.rs
  • baml_language/crates/bex_events/src/value/proto/bamlvalue.proto
  • baml_language/crates/bex_events/src/value/read.rs
  • baml_language/crates/bex_events/src/value/record.rs
  • baml_language/crates/bex_events/src/value/writer.rs
  • baml_language/crates/bex_project/src/lib.rs
  • baml_language/crates/bex_vm/src/vm.rs
  • baml_language/crates/bex_vm/tests/events.rs
  • baml_language/crates/bridge_ctypes/Cargo.toml
  • baml_language/crates/bridge_ctypes/src/handle_table.rs
  • baml_language/crates/bridge_ctypes/src/lib.rs
  • baml_language/crates/bridge_ctypes/src/value_encode.rs
  • baml_language/crates/bridge_wasm/src/lib.rs
💤 Files with no reviewable changes (1)
  • baml_language/crates/baml_pack_host/Cargo.toml
✅ Files skipped from review due to trivial changes (2)
  • baml_language/crates/baml_compiler2_hir/Cargo.toml
  • baml_language/crates/bex_project/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (13)
  • baml_language/crates/bex_events/src/value/mod.rs
  • baml_language/crates/baml/src/main.rs
  • baml_language/crates/bex_events/src/value/proto/bamlvalue.proto
  • baml_language/crates/baml_release/src/lib.rs
  • baml_language/crates/baml_compiler2_mir/src/pretty.rs
  • baml_language/crates/bex_engine/src/trace_heap.rs
  • baml_language/crates/bex_events/src/history/boundary_writer.rs
  • baml_language/crates/bex_events/src/value/artifact.rs
  • baml_language/crates/bex_events/src/history/mod.rs
  • baml_language/crates/bex_engine/tests/prof_gate.rs
  • baml_language/crates/bex_events/src/value/record.rs
  • baml_language/crates/baml_lsp_server/src/playground_server.rs
  • baml_language/crates/bex_vm/src/vm.rs

# Conflicts:
#	baml_language/crates/baml_compiler2_mir/src/lower.rs
#	baml_language/crates/baml_tests/snapshots/compiles/type_builder_errors/baml_tests__compiles__type_builder_errors__06_codegen.snap
#	baml_language/crates/baml_tests/snapshots/diagnostic_errors/runtime_id_misuse/baml_tests__diagnostic_errors__runtime_id_misuse__04_tir.snap
#	baml_language/crates/baml_tests/snapshots/diagnostic_errors/runtime_id_misuse/baml_tests__diagnostic_errors__runtime_id_misuse__05_diagnostics.snap
#	baml_language/crates/bex_engine/Cargo.toml
#	baml_language/crates/bex_vm/src/vm.rs
#	baml_language/crates/bex_vm_types/src/lib.rs
#	baml_language/crates/bex_vm_types/src/types.rs
@vercel
vercel Bot temporarily deployed to Preview – beps June 27, 2026 01:00 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 27, 2026 01:07 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 27, 2026 01:12 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 27, 2026 01:18 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 27, 2026 01:29 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 27, 2026 03:02 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 27, 2026 03:08 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 27, 2026 03:14 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 27, 2026 03:19 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 27, 2026 03:30 Inactive
@rossirpaulo
rossirpaulo added this pull request to the merge queue Jun 27, 2026
Merged via the queue into canary with commit 301a949 Jun 27, 2026
60 checks passed
@rossirpaulo
rossirpaulo deleted the paulo/data-ingestion branch June 27, 2026 04:13
aaronvg added a commit that referenced this pull request Jun 30, 2026
The bridge_wasm runtime + pkg-playground protocol renamed runId -> boundaryId
(#3844/#3864), but the website worker still read msg.runId and forwarded
notification.runId — both undefined at runtime, so run snapshots/subscriptions
never matched and the run UI never updated.

- rename runId -> boundaryId across run handlers (cancelRun, respondToInput,
  respondToEnv, snapshot, subscribe) and the runSnapshot/runCursorExpired
  notification forwarders
- add the missing listHistory/openHistory/readValue handlers and the
  historyList/valueBody notification forwarders (matches app-promptfiddle)

Co-Authored-By: Claude Opus 4.8 <[email protected]>
meefs pushed a commit to meefs/baml that referenced this pull request Jun 30, 2026
…tx)) (BoundaryML#3886)

## What

`catch (e, ctx)` now binds a second value — an **`ErrorContext`** —
giving BAML implicit error chaining in the style of Python's
`__context__`. When code throws a *new* error while handling another,
the new error's `ctx.cause` automatically links back to the error being
handled, and rendering the context prints the whole chain oldest-first:

```
<original error + stack trace>

During handling of the above error, another error occurred:

<new error + stack trace>
```

This completes BEP-042 (alongside `defer` BoundaryML#3785 and `cleanup` BoundaryML#3835).

## The type

```baml
class ErrorContext {
  error       unknown
  stack_trace StackTrace
  cause       ErrorContext?
}
```

- `baml.errors.ErrorContext`, registered in `baml_builtins2::ALL`.
- pure-BAML `root_cause()` walks `cause` to the original failure.
- `implements baml.ToString` — the native renderer prints the full
chain.

**Breaking change:** the optional second binding of `catch (e, ctx)`
changes type from `StackTrace` to `ErrorContext` (the trace is now
`ctx.stack_trace`).

## How it works

`cause` is computed **lazily at the cold throw funnel** — no in-flight
register, no per-edge teardown opcode. When a throw unwinds, the VM
walks the live frames read-only; if the throw's PC lies in an active
handler body, the error that handler is handling becomes the new error's
`cause`. Handler-body extents live in a side table
(`handler_context_table`), one **per-block** range so layout-fragmented
handler bodies are covered exactly — no over-covering the gaps between
fragments.

The teardown design was chosen after studying how CPython/Go/JVM/.NET/V8
represent "currently-handling" state from source. Conclusion: BAML keeps
no teardown opcode — the same move it already made going from
`PushHandler`/`PopHandler` to exception tables. CPython is the lone VM
that keeps a per-edge teardown opcode, and only for two constraints BAML
provably lacks.

### Coverage

- **Nested `catch { throw }`** — `throw B` while handling `A` ⇒ `B.cause
= A`.
- **Sibling defers** — `defer{throw A}; defer{throw B}; defer{throw C};
throw X` runs LIFO and chains `A → B → C → X`; `root_cause()` reaches
`X`.

### Rethrow

A bare re-raise (`throw e`, the no-match fall-through, `ThrowIfPanic`)
is flagged as a *rethrow* and does **not** add a chain link — it
re-propagates the same error rather than recording a new one (pairs with
the `Rethrow` mechanism from BoundaryML#3844, so the no-match fall-through doesn't
self-link onto its own context).

> **Known limitation:** a prior chain carried by a rethrown value is not
preserved across the re-raise (its next catch sees `cause = null`). This
is a deliberate conservative choice — recovering it would need a
value→context association we don't track, and reusing the cause-walk
result instead would mis-attribute a nested outer-binding rethrow
(binding the inner handler's error).

## Validation

- New acceptance tests, **all proven non-vacuous** (each fails when its
fix is reverted): root-cause-is-self, nested-catch chaining, two
slot-liveness hazards, no-rethrow-self-link, layout-gap non-coverage,
sibling-defer chain-to-root-cause.
- `errorcontext` 7/7 · `exceptions` · `defer` · `cleanup` ·
`bytecode_format` · `bex_vm_types` green · full `baml_tests --lib`
**1714/0**, no codegen snapshot drift · pre-commit clippy/fmt green.

## Follow-up (separate PR)

Surfacing the cause chain in the BEX tracing system (so `RunError`
carries the `cause`) builds on this and lands separately.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added error context tracking with chained causes and readable,
stack-trace-aware error output.
* Improved exception handling so nested errors preserve the original
failure context during unwinding.

* **Bug Fixes**
* Fixed cause-chain resolution in nested handlers and edge cases
involving deferred or fragmented handler bodies.
* Preserved stack-trace/context data even when it appears unused,
improving reliability of error reporting.

* **Tests**
* Added coverage for error-context chaining and updated stack-trace
snapshots to reflect richer output.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

This branch was previously deployed

3 inactive deployments
Preview – promptfiddle — 78f69426 Deployed Jun 27, 2026 by vercel[bot]
Preview – promptfiddle2 — 78f69426 Deployed Jun 27, 2026 by vercel[bot]
Preview – beps — 78f69426 Deployed Jun 27, 2026 by vercel[bot]
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