Skip to content

feat(runtime): workflow correlation ID threading (closes #86, FWS-2)#98

Merged
initializ-mk merged 1 commit into
mainfrom
feat/issue-86-workflow-correlation-ids
Jun 5, 2026
Merged

feat(runtime): workflow correlation ID threading (closes #86, FWS-2)#98
initializ-mk merged 1 commit into
mainfrom
feat/issue-86-workflow-correlation-ids

Conversation

@initializ-mk
Copy link
Copy Markdown
Contributor

Summary

  • Threads orchestrator correlation IDs through every audit event so an A2A-compatible orchestrator can stitch together the events emitted by multiple Forge agents participating in one workflow run.
  • Forge agents extract four headers at the A2A dispatch boundary — X-Workflow-ID, X-Workflow-Stage-ID, X-Workflow-Step-ID, X-Invocation-Caller — into a WorkflowContext carried on context.Context. A new AuditLogger.EmitFromContext auto-tags workflow_id / stage_id / step_id / invocation_caller on every event emitted under that ctx.
  • Header names are deliberately vendor-neutral: any orchestrator (initializ Command, custom registries, third-party platforms) can drive Forge's correlation surface without adopting a vendor prefix.
  • Backward compatible: direct A2A invocations (no headers) produce audit JSON byte-for-byte identical to the pre-FWS-2 shape — the four fields are omitempty. Existing auditLogger.Emit(...) callers continue to work unchanged.
  • Outbound propagation (WorkflowContext.ApplyToHTTPHeaders) is exposed for tools that explicitly call workflow peers; auto-propagation on every outbound HTTP request is deliberately off to prevent leaking workflow identity to third-party APIs (the egress proxy can't tell a peer agent from a vendor endpoint).

Wiring

Layer File
Core types + helpers forge-core/runtime/workflow.go (new)
Audit fields + EmitFromContext forge-core/runtime/audit.go
JSON-RPC dispatcher reads headers → ctx forge-cli/server/a2a_server.go
REST /tasks/send + /tasks/sendSubscribe handlers forge-cli/runtime/runner.go (also migrated in-request EmitEmitFromContext)
Auth audit callback forge-cli/runtime/runner.go (pulls headers directly from req.Header since auth runs before dispatcher)

Tests

  • forge-core/runtime/workflow_test.go — 8 tests covering IsZero, header extraction (all/missing/partial), ctx round-trip, ApplyToHTTPHeaders, headers↔ctx↔headers round-trip
  • forge-core/runtime/audit_workflow_test.go — 6 tests covering EmitFromContext tagging from ctx, omission when ctx empty (backward compat), explicit fields take precedence, also tags CorrelationID/TaskID, partial WorkflowContext omits absent sub-fields, classic Emit path unchanged
  • forge-cli/server/a2a_server_workflow_test.go — 2 HTTP end-to-end tests: dispatcher extracts headers into ctx; missing headers yield IsZero WorkflowContext

Docs

  • docs/security/workflow-correlation.md (new) — header table, flow diagram, audit shape, outbound propagation guidance, backward-compat notes, file-by-file wiring table
  • docs/security/audit-logging.md — Workflow correlation subsection
  • docs/security/overview.md — note about workflow-tagging in Audit Logging section
  • README.md — Workflow Correlation entry under Security
  • CHANGELOG.md — Unreleased entry

Test plan

  • go test -race -count=1 ./forge-core/runtime/... — pass
  • go test -race -count=1 ./forge-cli/server/... — pass
  • go test -race -count=1 ./forge-cli/runtime/... — pass
  • golangci-lint run across forge-core/runtime + forge-cli/server + forge-cli/runtime — 0 issues
  • gofmt -l clean on all touched files
  • CI green on push

Forge agents now extract orchestrator correlation headers
(X-Workflow-ID, X-Workflow-Stage-ID, X-Workflow-Step-ID,
X-Invocation-Caller) at the A2A dispatch boundary (JSON-RPC + REST),
stash them as a WorkflowContext in context.Context, and auto-tag every
audit event with workflow_id / stage_id / step_id / invocation_caller
via a new AuditLogger.EmitFromContext.

Direct A2A invocations (no orchestrator headers) leave the fields
unset — emitted JSON is byte-identical to the pre-FWS-2 shape, so
existing audit consumers keep working.

Header names are deliberately vendor-neutral: any A2A-compatible
orchestrator can drive the correlation surface without adopting a
vendor prefix. WorkflowContext.ApplyToHTTPHeaders is exposed for tools
that want to propagate headers onto outbound agent-to-agent A2A calls;
auto-propagation is off by default to prevent leaking workflow
identity to third-party APIs.

See docs/security/workflow-correlation.md for the full reference.
@initializ-mk initializ-mk merged commit 96be89f into main Jun 5, 2026
10 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.

1 participant