feat(explore): dynamic-dispatch boundary surfacing — announce where a flow ends instead of guessing edges (#687) (#835)

* feat(explore): announce dynamic-dispatch boundaries when a flow can't connect statically (#687)

When buildFlowFromNamedSymbols can't connect the agent's named symbols, scan
the disconnected symbols' bodies (query-time, deterministic, zero graph
mutation) for dynamic-dispatch forms — computed member calls, getattr,
reflection, typed message buses, runtime-keyed emits, Proxy — and announce
the exact site where the static path ends, with candidate runtime targets
when a dispatch key is statically visible. The honest alternative to
guessing edges: surface the boundary, don't fabricate the bridge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(agent-eval): ab-new-vs-baseline survives files added since the baseline ref

A single multi-file 'git checkout <ref> --' with one unknown pathspec checks
out nothing, so the baseline arm silently ran the NEW build. Check out
per-file and remove files that don't exist on the baseline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(playbook): boundary surfacing as the mechanism floor for non-gateable dispatch (#687)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(explore): render a direct synthesized hop between two named symbols (#687)

A 2-node chain populates pathIds but renders nothing (Flow needs >=3), and
the dynamic-links section skipped its edge as 'already in the main chain' —
so a custom EventBus emit→handler connection was invisible. Skip-as-in-chain
now applies only when a chain actually renders, and the boundary scan treats
short-chain endpoints as connected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-06-12 11:26:33 -05:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 848fde9f59
commit df6f4bec43
6 changed files with 896 additions and 5 deletions
@@ -161,6 +161,18 @@ were found). Confirm it's dynamic by reading the break symbol's body.
- `on('e',fn)` + `emit('e')`**EventEmitter synthesizer** (§3b).
- Inline handler not a node → **named:** extraction (already done generically in
`tree-sitter.ts`); **anonymous:** synthesizer link-through-body (not yet built).
- Dispatch that CAN'T be precision-gated as a class (runtime-keyed `table[key](...)`,
`getattr(self, expr)`, reflection, typed mediator buses, `new Proxy`) → **boundary
surfacing** (`src/mcp/dynamic-boundaries.ts`, #687): explore ANNOUNCES the dispatch
site where the static path ends — file:line, form, and candidate targets when the
key is statically visible — instead of synthesizing an edge. Query-time only, zero
graph mutation, fires only when the asked-about flow fails to connect. This is the
deliberate floor for the frontier: a wrong edge poisons the map (silent beats
wrong), but an honest "the flow continues at THIS site, likely into THESE
candidates" still saves the read-reconstruction spiral. When a boundary form later
proves precision-gateable on real repos (e.g. a same-repo literal-key command bus),
promote it to a synthesizer channel and the boundary note disappears on its own —
the flow then connects.
### Step 4 — Implement
- **Resolver:** add to `src/resolution/frameworks/<lang>.ts` — a `resolve()` branch +