Skip to content

feat(runtime): thread real emitted events through LocalExecutor, retire output-JSON convention - #1053

Closed
enricopiovesan wants to merge 1 commit into
mainfrom
claude/issue-996-local-executor-events
Closed

feat(runtime): thread real emitted events through LocalExecutor, retire output-JSON convention#1053
enricopiovesan wants to merge 1 commit into
mainfrom
claude/issue-996-local-executor-events

Conversation

@enricopiovesan

Copy link
Copy Markdown
Collaborator

Summary

LocalExecutor::execute returned a bare Value, discarding any events a
native or WASM-backed capability emitted during workflow-internal node
execution (ArtifactRouter, used directly by workflows.rs) and hardcoding
emitted_events: Vec::new() on the live PlacementRouter path
(BoundLocalExecutor). workflows.rs also read a JSON "emitted_events"
convention key out of the node output, rather than a structured field.

This PR extends LocalExecutor::execute to return
LocalExecutionOutput { value, emitted_events: Vec<TraverseEvent> }, threads
real WASM-sourced events through both call paths, validates natively-emitted
events against the capability's emits declaration and Subscribable
service_type before they're used for anything (mirroring
PlacementRouter Step 5's WASM-boundary validation), and publishes
workflow-node events to EventBroker for Subscribable capabilities
(best-effort — a publish failure does not fail the workflow step). The old
JSON "emitted_events" convention key is removed. All ~21 LocalExecutor
implementors across traverse-runtime, traverse-mcp, and traverse-cli
are migrated to the new return type.

Governing Spec

  • 101-local-executor-event-emission
  • 518-durable-local-datastore
  • 006-runtime-request-execution
  • 001-foundation-v0-1

101-local-executor-event-emission (ADR-0037) is the primary spec; it
governs crates/traverse-runtime/src/{lib,artifact_router,workflows}.rs.
518-durable-local-datastore covers crates/traverse-runtime/tests/.
006-runtime-request-execution covers
crates/traverse-runtime/examples/load_workspace_app_state.rs.
001-foundation-v0-1 covers crates/traverse-cli/ and
crates/traverse-mcp/ (mechanical LocalExecutor return-type migration
only; no behavioral change to those crates).

Changes

  • LocalExecutionOutput { value, emitted_events } replaces the bare Value
    return type on LocalExecutor::execute.
  • BoundLocalExecutor (native PlacementRouter path) validates natively
    emitted events against emits/Subscribable before returning them in
    ExecutorOutput, so PlacementRouter Step 5 publishes real events instead
    of the previous hardcoded empty vec.
  • ArtifactRouter::execute returns the real emitted_events from
    WasmExecutor (already ABI-validated) instead of discarding them. It does
    not hold an EventBroker or publish internally — it's used both directly
    by workflows.rs and, via BoundLocalExecutor, by PlacementRouter, so
    publishing there would double-publish on the live Runtime::execute()
    path.
  • workflows.rs's traverse_workflow validates natively-emitted events the
    same way, publishes to EventBroker for Subscribable capabilities
    (best-effort), and reads emitted events from
    LocalExecutionOutput.emitted_events instead of parsing a JSON
    "emitted_events" key out of the node output. The JSON-convention parser
    function is deleted.
  • All LocalExecutor implementors (production and test doubles) across the
    workspace updated to the new return type.

Validation

  • cargo test --workspace — all suites green (traverse-runtime lib: 293
    tests, including 3 new BoundLocalExecutor/PlacementRouter tests for
    declared/undeclared/non-Subscribable native events, 2 new
    workflow-node → EventBroker publish tests, and a new ArtifactRouter
    real-WASM-success test)
  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • cargo fmt --all --check — clean
  • bash scripts/ci/coverage_gate.sh — passed;
    traverse-runtime: 100.00% (19510/19510 lines),
    traverse-contracts: 100.00%, traverse-embedder: 100.00%,
    traverse-mcp: 98.89%, traverse-cli-rs: 87.16%,
    traverse-swift-host: 84.03% (all at or above their configured floor)
  • BASE_SHA=origin/main bash scripts/ci/local_preflight.sh — pending

…re output-JSON convention

LocalExecutor::execute now returns LocalExecutionOutput { value, emitted_events }
instead of a bare Value, so both BoundLocalExecutor (PlacementRouter path) and
ArtifactRouter (workflow-internal node execution) carry real WASM-sourced
events instead of discarding them. Native-emitted events are validated against
the capability's `emits` list and Subscribable service_type before use.
workflows.rs now publishes to EventBroker and reads emitted events from the
structured field, removing the old JSON "emitted_events" key convention.

Migrates all ~21 LocalExecutor implementors across traverse-runtime,
traverse-mcp, and traverse-cli to the new return type.

Governing spec: 101-local-executor-event-emission (ADR-0037)

Closes #996

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@enricopiovesan

Copy link
Copy Markdown
Collaborator Author

Superseded by #1024, which implemented and merged this exact scope (LocalExecutor event emission across the same 11 files) on 2026-08-09, before this PR was ready. Issue #996 and its Project 1 item are already Done. Closing without merging to avoid duplicate/conflicting work.

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