Skip to content

feat(blocks): codegen — emit each block once, per-block trace seam, multi-edge throw - #206

Merged
07prajwal2000 merged 1 commit into
Fluxify-rest:mainfrom
07prajwal2000:feature/codegen-block-functions
Aug 6, 2026
Merged

feat(blocks): codegen — emit each block once, per-block trace seam, multi-edge throw#206
07prajwal2000 merged 1 commit into
Fluxify-rest:mainfrom
07prajwal2000:feature/codegen-block-functions

Conversation

@07prajwal2000

Copy link
Copy Markdown
Collaborator

Why

Codegen inlined each block's continuation as a source string, so a shared tail downstream of a diamond was re-emitted once per branch (multiplying artifact size, compile time, JIT work), and edgeTo silently dropped every edge past the first on a handle. This also blocked per-block tracing and orchestration backtracking, which both need a stable per-block boundary.

What

  • Compiles each reachable block to a named async function ($block_N); a shared continuation is called, never duplicated. Reachability/emission order computed via one DFS pass (collectReachable), separate from emission.
  • edgeTo throws when a handle has more than one outgoing edge instead of dropping the extras; validateEdges() surfaces this at compile time for the whole graph, not just the reachable subset.
  • New per-block trace seam: ctx.trace?.recordSpan(...), gated by a $trace hoisted once per invocation — zero allocation/emission when unset. Terminal blocks report via a new node.complete() on EmitNode; response.ts migrated.
  • Artifacts compile to a small factory (/* fluxify-compiled-route-factory */ marker) instantiated via instantiateCompiled; old inline-function artifacts still run so a rolling worker update doesn't break in-flight artifacts.

Bug found + fixed in review

Loop bodies (for/foreach, via EmitNode.body()) never marked their own block as "reported" before calling into the executor block, unlike next(). So when an executor block inside a loop threw, the loop block's own catch also fired — recording a second, misattributed failure span under the loop's blockId in addition to the executor's correct one. Fixed by setting $recorded = true before the body call, matching next(). Covered by a new regression test.

Test plan

  • bun test packages/blocks — 118 pass, 0 fail (added: shared-tail dedup, linear-source-across-diamonds, loop executor precedence/response propagation, trace span emission, error-span attribution incl. the loop misattribution fix, multi-edge-throw)
  • bun run --cwd packages/blocks lint (tsgo --noEmit) — clean
  • Manually reverted the fix and reran the new regression test to confirm it fails without it

Closes #193

…dge throw

Compiles each block to a named async function, deduping shared tails
instead of re-emitting them per branch. edgeTo throws on >1 edge for a
handle instead of silently dropping. Adds a per-block trace seam
(ctx.trace) that is zero-cost when unset.

Fixes a misattribution bug: loop bodies (for/foreach) never marked
their block as reported before delegating to the executor block, so
an executor throw was recorded twice — once correctly under the
executor's blockId, once wrongly under the loop's.

Closes Fluxify-rest#193
@07prajwal2000
07prajwal2000 added this pull request to the merge queue Aug 6, 2026
Merged via the queue into Fluxify-rest:main with commit cd96ffa Aug 6, 2026
11 checks passed
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.

P1: codegen — emit each node once, per-block seam, multi-edge handles

1 participant