Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changeset/document-source-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@stackables/bridge": patch
"@stackables/bridge-core": patch
"@stackables/bridge-compiler": patch
"@stackables/bridge-graphql": patch
"@stackables/bridge-parser": patch
---

Move Bridge source metadata onto BridgeDocument.

Parsed documents now retain their original source text automatically, and can
optionally carry a filename from parse time. Runtime execution, compiler
fallbacks, GraphQL execution, and playground formatting now read that metadata
from the document instead of requiring callers to thread source and filename
through execute options.
14 changes: 14 additions & 0 deletions .changeset/runtime-error-tool-formatting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
"@stackables/bridge": patch
"@stackables/bridge-core": patch
---

Improve formatted runtime errors for missing tools and source underlines.

`No tool found for "..."` and missing registered tool-function errors now carry
Bridge source locations when they originate from authored bridge wires, so
formatted errors include the filename, line, and highlighted source span.
Control-flow throw fallbacks now preserve their own source span, so
`?? throw "..."` highlights only the throw clause instead of the whole wire.
Caret underlines now render the full inclusive source span instead of stopping
one character short.
7 changes: 7 additions & 0 deletions .changeset/safe-path-panic-formatting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@stackables/bridge": patch
"@stackables/bridge-core": patch
"@stackables/bridge-compiler": patch
---

Fix segment-local `?.` traversal so later strict path segments still fail after a guarded null hop, and preserve source formatting for `panic` control-flow errors.
11 changes: 11 additions & 0 deletions .changeset/ternary-condition-source-mapping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@stackables/bridge": patch
"@stackables/bridge-core": patch
"@stackables/bridge-compiler": patch
"@stackables/bridge-parser": patch
---

Improve runtime error source mapping for ternary conditions and strict path traversal.

Runtime and compiled execution now preserve clause-level source spans for ternary conditions and branches, so formatted errors can highlight only the failing condition or selected branch instead of the whole wire.
Strict path traversal also now fails consistently on primitive property access in both runtime and AOT execution, keeping error messages and behavior aligned.
79 changes: 75 additions & 4 deletions packages/bridge-compiler/performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ Tracks engine performance work: what was tried, what failed, and what's planned.

## Summary

| # | Optimisation | Date | Result |
| --- | --------------------- | ---- | ------ |
| 1 | Future work goes here | | |
| # | Optimisation | Date | Result |
| --- | ------------------------------------ | ---------- | ------------------------------------------------ |
| 1 | Strict-path parity via `__path` | March 2026 | ✅ Done (correctness first, measurable slowdown) |
| 2 | Single-segment fast path via `__get` | March 2026 | ✅ Done (partial recovery on compiled hot paths) |

## Baseline (main, March 2026)

Expand Down Expand Up @@ -41,4 +42,74 @@ This table is the current perf level. It is updated after a successful optimisat

## Optimisations

### 1. Future work goes here
### 1. Strict-path parity via `__path`

**Date:** March 2026
**Status:** ✅ Done

**Why:**

Runtime source-mapping work tightened strict path traversal semantics so
primitive property access throws at the failing segment instead of silently
flowing through as `undefined`. Compiled execution still had some strict paths
emitted as raw bracket access, which caused AOT/runtime divergence in parity
fuzzing.

**What changed:**

`appendPathExpr(...)` was switched to route compiled path traversal through the
generated `__path(...)` helper so compiled execution matched runtime semantics.

**Result:**

Correctness and parity were restored, but this imposed a noticeable cost on the
compiled hot path because even one-segment accesses paid the generic loop-based
helper.

Observed branch-level compiled numbers before the follow-up optimisation:

| Benchmark | Baseline | With `__path` everywhere | Change |
| -------------------------------------- | -------- | ------------------------ | ------ |
| compiled: passthrough (no tools) | ~644K | ~561K | -13% |
| compiled: simple chain (1 tool) | ~612K | ~536K | -12% |
| compiled: flat array 1000 | ~27.9K | ~14.1K | -49% |
| compiled: array + tool-per-element 100 | ~58.7K | ~45.2K | -23% |

### 2. Single-segment fast path via `__get`

**Date:** March 2026
**Status:** ✅ Done

**Hypothesis:**

The vast majority of compiled property reads in the benchmark suite are short,
especially one-segment accesses. Running every one of them through the generic
`__path(base, path, safe, allowMissingBase)` loop was overpaying for the common
case.

**What changed:**

- Added a generated `__get(base, segment, accessSafe, allowMissingBase)` helper
for the one-segment case.
- Kept the strict primitive-property failure semantics from `__path(...)`.
- Left multi-segment accesses on `__path(...)` so correctness stays uniform.

**Result:**

This recovered a meaningful portion of the compiled regression while preserving
the stricter source-mapping semantics.

| Benchmark | Before `__get` | After `__get` | Change |
| -------------------------------------- | -------------- | ------------- | ------ |
| compiled: passthrough (no tools) | ~561K | ~639K | +14% |
| compiled: simple chain (1 tool) | ~536K | ~583K | +9% |
| compiled: flat array 1000 | ~14.1K | ~15.7K | +11% |
| compiled: nested array 20×10 | ~36.0K | ~39.1K | +9% |
| compiled: array + tool-per-element 100 | ~45.2K | ~50.0K | +11% |

**What remains:**

Compiled performance is much closer to baseline now, but still below the March
2026 table on some heavy array benchmarks. The obvious next step, if needed, is
specialising short strict paths of length 2–3 rather than routing every
multi-segment path through the generic loop helper.
Loading
Loading