Skip to content

feat(grpc): trace and events for ExecuteAction - #1778

Merged
HuiJun merged 16 commits into
developfrom
feat/execute-action-trace-events
Oct 31, 2026
Merged

HuiJun merged 16 commits into
developfrom
feat/execute-action-trace-events

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

What and why

ExecuteAction gains a run trace and mid-run events, mirroring what ExecuteState already has, so a client (and the homepage hero's coming action scene) can watch an action run step by step and send a signal to an accept that is waiting for it.

Protocol (api/proto/sysml.proto, bindings regenerated for Go, Python, Node, Java, Rust, Julia)

  • ExecuteActionRequest.trace (bool, field 10) asks for the run's trace; ExecuteActionResponse.trace (repeated DocumentEvent, field 9) and trace_dropped (field 10) answer it, bounded as the state trace is. A run that fails or deadlocks still returns the records it produced up to the failure.
  • ExecuteActionRequest.events (repeated string, field 11) are the signals posted to the performing object in order. The interleaving is the REPL's %send: the run goes until it completes or every token waits, the next event is posted, the waiting accept takes it on the next step, and so on; an event no accept waits for, or one posted after completion, is an error. Events need performer_symbol_id (INVALID_ARGUMENT otherwise); an explore schedule rejects both trace and events.
  • DocumentEvent gains token (14), step (15), feature (16) and value (17), used by the new action record kinds.
  • Capability action_trace, advertised by the service and the wasm module; a service without it refuses trace: true with UNIMPLEMENTED naming the capability (internal/frontend/grpc/action_trace_test.go, as the state_trace refusal is pinned; the conformance harness has no way to withhold a capability, so the traced run and the event delivered to a waiting accept are the conformance fixtures: execute_action_trace, execute_action_events_accept, execute_action_events_waiting).

Runtime (internal/exec/runtime)

  • New TraceKinds recorded by the action executor at its real steps, never reconstructed afterwards: step (a token arriving at a node, with token id, executor step and clock instant), wait (an accept waiting, naming the event), accept (the one it took), decide (the alternatives and the branch taken, like choice), assign (the feature and the value the engine wrote), complete. TraceRecord.Text() renders them; Line() reports them as unprinted, so -trace / %trace output is unchanged.
  • Context.ExecuteActionWithEvents and Context.DeliverEvents implement the event interleaving; with feat(engine): run state machines and actions on the clock (advance), with a clocked hero scene #1777's clocked runs merged, ExecuteActionAdvancedBy/startActionAdvancedBy take the events too and post them before the clock advances.

Service, engine, clients

  • sysml-grpc (run_options.go, service.go) and the in-browser engine (engine.go, json.go: trace, events, trace/traceDropped on the JSON mirrors) honour the new fields with the same validation.
  • Every client takes trace/events on its ExecuteAction surface, checks action_trace before asking for a trace, decodes the new DocumentEvent fields and reports the partial trace on failure: Go (client/opensysml), Python, Node (incl. the wasm transport), Java, Rust, Julia, MATLAB; the MCP execute_action tool takes trace/events and prints the records. docs/reference/* describe the fields everywhere clock_step was documented.

Mission check (internal/frontend/grpc/mission_sequence_test.go, over examples/runtime-showcase/mission-sequence.sysml): LunarMission on apollo11 traced without events stops waiting at awaitGo for GoForDescent (reported as a deadlock with the partial trace, not as success); with events: ["GoForDescent"] it completes with landed = true, returned = true, remaining = 480 [m/s]; apollo8 takes the transEarthInjection branch. LunarMissionUnordered completes legally on today's runtime rather than failing at initialization — the test pins what the engine does, and the hero scene will show the engine's actual answer.

Landing order. #1777 (feat/engine-state-advance, now in develop) was merged into this branch as a merge commit (no rebase) with the resolution its body describes (events threaded through the advance-aware runs, runAction choosing by advance); develop is merged in up to #1777/#1779/#1740, so the diff is this PR's own changes. Earlier, the develop merge (with #1773) the one conflict was the Rust client's capability import list, resolved as the union, and the protobuf stubs were regenerated on the merged tree (make proto-buf python-proto proto-ts proto-rust), which changed nothing. #1782 builds the homepage hero's Apollo 11 action scene on this surface and lands after this one.

How it was verified

On the merged head (this branch with #1777's head and develop merged in) the whole matrix was re-run:

  • go build ./... && go vet ./... && gofmt -l . — clean, gofmt prints nothing.
  • go test ./... — all 124 packages ok on the feat(engine): run state machines and actions on the clock (advance), with a clocked hero scene #1777 merge (cmd/sysml alone takes ~4.5 min here, so the run used -timeout 40m); after merging develop, every runtime, frontend, queryexec, tests/grpc, tests/wasm and client/opensysml package re-run ok.
  • cd client/node && rm -rf build/wasm build/service && npm run build && npm test — 473 pass, 0 fail (lint and typecheck clean).
  • cargo fmt --all -- --check && cargo clippy --all-targets -- -D warnings && cargo test --workspace against a sysml-grpc built from the tree (RUST_MIN_STACK raised for the pre-existing deep-nesting test) — all 13 test binaries pass; Python pytest — 1575 passed, 141 skipped (the two test_version checks fail only because this machine's editable install points at another checkout); Java mvn -B -q -f client/java/pom.xml test — 356 tests green on JDK 21; Julia Pkg.test — green.
  • gRPC conformance (tests/grpc), the wasm JSON surface (tests/wasm), the runtime trace-kind and robustness tests (internal/exec/runtime), the service tests (internal/frontend/grpc, incl. mission_sequence_test.go) and the MCP tool tests all pass on the merged head.
  • No examples/ or tests/testdata file changed, so the pilot differential baselines did not move.

MATLAB: Octave is not installed here; the client change is covered by CI's MATLAB/Octave job (the string() call that job rejected is fixed).

Checklist

  • make test and make lint pass locally
  • Tests added or updated for the change
  • Documentation extended where it already covers the surface (see CONTRIBUTING.md)
  • Changelog entry added as changes/unreleased/<slug>.<section>.md, not as an edit to CHANGELOG.md
  • baselines regenerated and make docs-counts run if a gate count moved (compliance rows need nothing: the census is counted at docs build)
  • No internal work-item labels (waves, slices, F4, K5) in the body, docs, or changelog

Link to Devin session: https://nasa-jpl-demo.devinenterprise.com/sessions/ea449771e507498985e128186c5ad7e5
Open in Devin Desktop: https://nasa-jpl-demo.devinenterprise.com/desktop/session/ea449771e507498985e128186c5ad7e5?variant=devin
Requested by: @HuiJun

ExecuteActionRequest takes trace and events, ExecuteActionResponse carries the
run's trace as DocumentEvent records: the action executor records each token
step, wait, accept, decision, assignment and the completion as typed records
that print no line, and events are posted to the performer in turn as the run
waits, as the REPL's %send does. The gRPC service and the wasm engine advertise
the action_trace capability.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

devin-ai-integration Bot and others added 2 commits October 30, 2026 18:19
…d Python clients

Regenerates the protobuf stubs for the request and response fields.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…and Java clients

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration Bot and others added 6 commits October 30, 2026 18:39
…and MATLAB clients and the MCP tool

Co-Authored-By: jason.han <hanhuijun@gmail.com>
… client and the reference docs

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…nce example

Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
…ve-compatible token decoding; lint

Co-Authored-By: jason.han <hanhuijun@gmail.com>
…feat/execute-action-trace-events

Co-Authored-By: jason.han <hanhuijun@gmail.com>

# Conflicts:
#	internal/exec/runtime/context.go
#	internal/frontend/engine/engine.go
#	internal/frontend/engine/json.go
#	internal/frontend/grpc/run_options.go
#	internal/frontend/grpc/service.go
@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review October 30, 2026 19:20
…n-trace-events

Co-Authored-By: jason.han <hanhuijun@gmail.com>

# Conflicts:
#	client/rust/opensysml/src/operations.rs
devin-ai-integration[bot]

This comment was marked as resolved.

…alues, forward Rust/Java action options

ExecuteActionWithEvents lets go of a performance it started when the run fails, as a plain run
does; the assign record carries the value the target holds once written; the Rust conformance
adapter forwards trace and events and keeps a failed run's partial trace; Rust and Java state runs
refuse RunOptions/ExecutionOptions events, which are an action run's.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…ecord

A qualified target is not read back, since a nearer local of the name would answer instead.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration Bot and others added 3 commits October 30, 2026 20:36
The assign record of a qualified target reads the feature as a reader of the qualifier would —
the frame of a run of the owner, else the performing object — so a shaped write is recorded as
held and a local sharing the name cannot answer for it.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
Co-Authored-By: jason.han <hanhuijun@gmail.com>
@HuiJun
HuiJun merged commit df2bc17 into develop Oct 31, 2026
35 of 59 checks passed
@HuiJun
HuiJun deleted the feat/execute-action-trace-events branch October 31, 2026 06:05
devin-ai-integration Bot added a commit that referenced this pull request Oct 31, 2026
….0 record

Name develop df2bc17 as the candidate of the 0.12.0 performance
record and account for each merge after e022cbc: #1793, #1794,
#1787, #1788, #1752 and #1775 Go-neutral by diff; #1792 re-probed on
the export rows at 86fa09e (neutral); #1795 and #1791 measured at
a37809a on every row set (load and runtime rows unchanged,
BatchSatisfy one allocation per assertion, export rows +0.1 %);

Co-Authored-By: jason.han <hanhuijun@gmail.com>
#1778 measured at df2bc17 on the runtime and gRPC rows (unchanged).
HuiJun added a commit that referenced this pull request Oct 31, 2026
* docs(perf): account for every merge up to develop df2bc17 in the 0.12.0 record

Name develop df2bc17 as the candidate of the 0.12.0 performance
record and account for each merge after e022cbc: #1793, #1794,
#1787, #1788, #1752 and #1775 Go-neutral by diff; #1792 re-probed on
the export rows at 86fa09e (neutral); #1795 and #1791 measured at
a37809a on every row set (load and runtime rows unchanged,
BatchSatisfy one allocation per assertion, export rows +0.1 %);

Co-Authored-By: jason.han <hanhuijun@gmail.com>
#1778 measured at df2bc17 on the runtime and gRPC rows (unchanged).

* docs(perf): account for #1797 and #1785 in the 0.12.0 record, candidate develop d16ca71

Co-Authored-By: jason.han <hanhuijun@gmail.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: jason.han <hanhuijun@gmail.com>
devin-ai-integration Bot added a commit that referenced this pull request Nov 1, 2026
Resolves the Node client conflicts with the client-parity and action-trace
work (#1766, #1786, #1778): ParseOptions keeps strictConformance alone,
ParseSourcesOptions extends it, connection.ts and model.ts read
options.strictConformance directly without the removed strictConformanceOf,
and the sources test of the removed strict alias becomes a strictConformance
test (an OpenSysML-only notation is a warning by default, an error strictly).
The merged tree's remaining references to the removed names (the sysml REPL
testing skill, a conversion.ts comment) are updated.

Co-Authored-By: jason.han <hanhuijun@gmail.com>
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