Skip to content

Cross-language Java→Go Temporal linking (starts_temporal_workflow by canonical name) #77

@avfirsov

Description

@avfirsov

Is your feature request related to a problem?

Gortex already resolves the Temporal Go→Go workflow→activity layer end-to-end (internal/resolver/temporal_calls.go, internal/parser/languages/golang_temporal.go) and tags the Java side (@ActivityInterface / @WorkflowInterface / @ActivityMethod / @WorkflowMethod / @SignalMethod / @QueryMethod / @UpdateMethod) with temporal_role and propagates roles to implementors via EdgeImplements.

What's missing is the cross-language bridge: when a Java service starts a workflow whose implementation lives in a Go repo, the two are connected only by a shared canonical name string — and gortex creates no edge between the Java node and the Go node. Concretely:

  • pickGoTemporalTarget (internal/resolver/temporal_calls.go) hard-filters n.Language != "go" and is fed only by Go worker.Register* calls, so a Java workflow-start can never land on a Go workflow.
  • The Java extractor captures @WorkflowMethod(name="...") / @ActivityMethod(name="...") arguments into edge.Meta["args"] (internal/parser/languages/java.go, via EmitAnnotationEdge) but never parses them — the resolver only ever uses the bare method name (from.Name), so the canonical Temporal type name (Java SDK default {InterfaceSimpleName}_{methodName}, or the explicit name=) is unavailable for matching.

Net effect: in a polyglot Temporal estate (Java services → Go workflows → Go activities), roughly half the call graph — the Java→Go hop — is invisible.

Describe the solution you'd like

Two coordinated pieces (naming them G2 then G1 by dependency order):

G2 — Java canonical Temporal name extraction. Parse the captured @WorkflowMethod(name=...) / @ActivityMethod(name=...) argument and compute the Java SDK default canonical name ({InterfaceSimpleName}_{methodName}) when no explicit name= is present. Store it on the node (e.g. temporal_name meta) so both languages key off the same canonical string.

G1 — Cross-language workflow bridge. Extend the resolver's temporal index so a Java workflow-start consumer (a WorkflowStub call on a @WorkflowInterface type, resolved to its @WorkflowMethod) can be linked to the Go workflow registered under the same canonical name, via a dedicated edge kind (proposed starts_temporal_workflow). The same mechanism extends to query/signal/update: a Java @QueryMethod(name="status") consumer matches a Go workflow.SetQueryHandler(ctx, "status", ...) provider.

Note: the Go-side provider data for query/signal/update (the via=temporal.handler edges) is being added in PR #PLACEHOLDER, so the Go half of the query/signal/update match is already on its way. This issue is specifically about the cross-language join + the Java canonical-name parsing it depends on.

Open design questions (why this is an issue, not a surprise PR):

  1. Edge model. A new starts_temporal_workflow edge kind, or reuse EdgeCalls with via=temporal.start meta (consistent with how temporal.stub / temporal.register are modeled today)?
  2. Index collision. Today normaliseTemporalKind collapses signal/query/update → workflow, so query handlers and workflow starts would share a byKindName bucket. A cross-language join needs these disambiguated — preference on how?
  3. Confidence tier. The Java↔Go link is by-string-name across a type-system boundary; should it be ast_resolved, or a lower inferred tier, given there's no compiler guarantee the names line up?
  4. Contract/validation scope (the plan's "Stage 5"). Worth surfacing a contract_mismatch when Java @WorkflowMethod params don't line up with the Go workflow signature, or keep that out of scope for now? (Note: blast-radius already works through the resolved edges with no temporal-specific code, since they're normal EdgeCallsexplain_change_impact traverses them today. So a separate temporal-contract type may be unnecessary.)

Use case

For MCP tools / CLI (get_callers, explain_change_impact): "who starts this Go workflow?" should surface the Java service that calls it; "what breaks if I change this Go workflow's signature?" should reach the Java callers. Today both stop at the language boundary.

Happy to implement this once the edge-model and confidence-tier questions are settled — wanted to align on design before sending a large cross-cutting PR.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions