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):
- 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)?
- 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?
- 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?
- 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 EdgeCalls — explain_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.
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) withtemporal_roleand propagates roles to implementors viaEdgeImplements.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-filtersn.Language != "go"and is fed only by Goworker.Register*calls, so a Java workflow-start can never land on a Go workflow.@WorkflowMethod(name="...")/@ActivityMethod(name="...")arguments intoedge.Meta["args"](internal/parser/languages/java.go, viaEmitAnnotationEdge) 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 explicitname=) 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 explicitname=is present. Store it on the node (e.g.temporal_namemeta) 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
WorkflowStubcall on a@WorkflowInterfacetype, resolved to its@WorkflowMethod) can be linked to the Go workflow registered under the same canonical name, via a dedicated edge kind (proposedstarts_temporal_workflow). The same mechanism extends to query/signal/update: a Java@QueryMethod(name="status")consumer matches a Goworkflow.SetQueryHandler(ctx, "status", ...)provider.Open design questions (why this is an issue, not a surprise PR):
starts_temporal_workflowedge kind, or reuseEdgeCallswithvia=temporal.startmeta (consistent with howtemporal.stub/temporal.registerare modeled today)?normaliseTemporalKindcollapses signal/query/update →workflow, so query handlers and workflow starts would share abyKindNamebucket. A cross-language join needs these disambiguated — preference on how?ast_resolved, or a lower inferred tier, given there's no compiler guarantee the names line up?contract_mismatchwhen Java@WorkflowMethodparams 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 normalEdgeCalls—explain_change_impacttraverses 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.