From d40df62c4682d097902b027f4b5866326b3c6b18 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 04:24:51 +0000
Subject: [PATCH 01/16] Initial plan
From 88889a93a3f02fe1dbc181cb36b8e0fe2acb2e61 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 04:47:28 +0000
Subject: [PATCH 02/16] feat: add OTLP trace export configuration to
observability section (#issue)
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/49301b6f-02ce-44b4-8fd5-1bc9a878d6cc
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
pkg/parser/schemas/main_workflow_schema.json | 18 +-
.../compiler_orchestrator_workflow.go | 4 +
pkg/workflow/frontmatter_types.go | 12 +-
pkg/workflow/observability_otlp.go | 86 +++++
pkg/workflow/observability_otlp_test.go | 332 ++++++++++++++++++
5 files changed, 450 insertions(+), 2 deletions(-)
create mode 100644 pkg/workflow/observability_otlp.go
create mode 100644 pkg/workflow/observability_otlp_test.go
diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json
index 66026536a35..303db6db17d 100644
--- a/pkg/parser/schemas/main_workflow_schema.json
+++ b/pkg/parser/schemas/main_workflow_schema.json
@@ -8328,6 +8328,17 @@
"type": "string",
"enum": ["on", "off"],
"description": "If set to 'on', append a compact observability section to the GitHub Actions job summary. Defaults to off when omitted."
+ },
+ "otlp": {
+ "type": "object",
+ "description": "OTLP (OpenTelemetry Protocol) trace export configuration.",
+ "properties": {
+ "endpoint": {
+ "type": "string",
+ "description": "OTLP collector endpoint URL (e.g. 'https://traces.example.com:4317'). Supports GitHub Actions expressions such as ${{ secrets.OTLP_ENDPOINT }}. When a static URL is provided, its hostname is automatically added to the network firewall allowlist."
+ }
+ },
+ "additionalProperties": false
}
},
"additionalProperties": false
@@ -9161,7 +9172,12 @@
"type": "number",
"minimum": 0
},
- "examples": [{ "my-custom-model": 2.5, "gpt-5": 3.0 }]
+ "examples": [
+ {
+ "my-custom-model": 2.5,
+ "gpt-5": 3.0
+ }
+ ]
},
"token-class-weights": {
"type": "object",
diff --git a/pkg/workflow/compiler_orchestrator_workflow.go b/pkg/workflow/compiler_orchestrator_workflow.go
index 4b6630d9221..57d5ff5d1ac 100644
--- a/pkg/workflow/compiler_orchestrator_workflow.go
+++ b/pkg/workflow/compiler_orchestrator_workflow.go
@@ -109,6 +109,10 @@ func (c *Compiler) ParseWorkflowFile(markdownPath string) (*WorkflowData, error)
// Extract YAML configuration sections from frontmatter
c.extractYAMLSections(result.Frontmatter, workflowData)
+ // Inject OTLP configuration: add endpoint domain to firewall allowlist and
+ // set OTEL env vars in the workflow env block (no-op when not configured).
+ c.injectOTLPConfig(workflowData)
+
// Merge features from imports
if len(engineSetup.importsResult.MergedFeatures) > 0 {
mergedFeatures, err := c.MergeFeatures(workflowData.Features, engineSetup.importsResult.MergedFeatures)
diff --git a/pkg/workflow/frontmatter_types.go b/pkg/workflow/frontmatter_types.go
index c4866381220..ca8c9afa3c8 100644
--- a/pkg/workflow/frontmatter_types.go
+++ b/pkg/workflow/frontmatter_types.go
@@ -117,9 +117,19 @@ type RateLimitConfig struct {
IgnoredRoles []string `json:"ignored-roles,omitempty"` // Roles that are exempt from rate limiting (e.g., ["admin", "maintainer"])
}
+// OTLPConfig holds configuration for OTLP (OpenTelemetry Protocol) trace export.
+type OTLPConfig struct {
+ // Endpoint is the OTLP collector endpoint URL (e.g. "https://traces.example.com:4317").
+ // Supports GitHub Actions expressions such as ${{ secrets.OTLP_ENDPOINT }}.
+ // When a static URL is provided, its hostname is automatically added to the
+ // network firewall allowlist.
+ Endpoint string `json:"endpoint,omitempty"`
+}
+
// ObservabilityConfig represents workflow observability options.
type ObservabilityConfig struct {
- JobSummary string `json:"job-summary,omitempty"`
+ JobSummary string `json:"job-summary,omitempty"`
+ OTLP *OTLPConfig `json:"otlp,omitempty"`
}
// FrontmatterConfig represents the structured configuration from workflow frontmatter
diff --git a/pkg/workflow/observability_otlp.go b/pkg/workflow/observability_otlp.go
new file mode 100644
index 00000000000..e5eb0a29c32
--- /dev/null
+++ b/pkg/workflow/observability_otlp.go
@@ -0,0 +1,86 @@
+package workflow
+
+import (
+ "fmt"
+ "net/url"
+ "strings"
+
+ "github.com/github/gh-aw/pkg/logger"
+)
+
+var otlpLog = logger.New("workflow:observability_otlp")
+
+// extractOTLPEndpointDomain parses an OTLP endpoint URL and returns its hostname.
+// Returns an empty string when the endpoint is a GitHub Actions expression (which
+// cannot be resolved at compile time) or when the URL is otherwise invalid.
+func extractOTLPEndpointDomain(endpoint string) string {
+ if endpoint == "" {
+ return ""
+ }
+
+ // GitHub Actions expressions (e.g. ${{ secrets.OTLP_ENDPOINT }}) cannot be
+ // resolved at compile time, so skip domain extraction for them.
+ if strings.Contains(endpoint, "${{") {
+ otlpLog.Printf("OTLP endpoint is a GitHub Actions expression, skipping domain extraction: %s", endpoint)
+ return ""
+ }
+
+ parsed, err := url.Parse(endpoint)
+ if err != nil || parsed.Host == "" {
+ otlpLog.Printf("Failed to extract domain from OTLP endpoint %q: %v", endpoint, err)
+ return ""
+ }
+
+ // Strip the port from the host so the AWF domain allowlist entry matches all ports
+ // (e.g. "traces.example.com:4317" → "traces.example.com").
+ host := parsed.Hostname()
+ otlpLog.Printf("Extracted OTLP domain: %s", host)
+ return host
+}
+
+// getOTLPEndpointEnvValue returns the raw endpoint value suitable for injecting as an
+// environment variable in the generated GitHub Actions workflow YAML.
+// Returns an empty string when no OTLP endpoint is configured.
+func getOTLPEndpointEnvValue(config *FrontmatterConfig) string {
+ if config == nil || config.Observability == nil || config.Observability.OTLP == nil {
+ return ""
+ }
+ return config.Observability.OTLP.Endpoint
+}
+
+// injectOTLPConfig modifies workflowData to incorporate any OTLP configuration:
+//
+// 1. When the endpoint is a static URL, its hostname is appended to
+// NetworkPermissions.Allowed so the AWF firewall allows outbound traffic to it.
+//
+// 2. OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_SERVICE_NAME are appended to the
+// workflow-level env: YAML block (workflowData.Env) so they are available to
+// every step in the generated GitHub Actions workflow.
+//
+// When no OTLP endpoint is configured the function is a no-op.
+func (c *Compiler) injectOTLPConfig(workflowData *WorkflowData) {
+ endpoint := getOTLPEndpointEnvValue(workflowData.ParsedFrontmatter)
+ if endpoint == "" {
+ return
+ }
+
+ otlpLog.Printf("Injecting OTLP configuration: endpoint=%s", endpoint)
+
+ // 1. Add OTLP endpoint domain to the firewall allowlist.
+ if domain := extractOTLPEndpointDomain(endpoint); domain != "" {
+ if workflowData.NetworkPermissions == nil {
+ workflowData.NetworkPermissions = &NetworkPermissions{}
+ }
+ workflowData.NetworkPermissions.Allowed = append(workflowData.NetworkPermissions.Allowed, domain)
+ otlpLog.Printf("Added OTLP domain to network allowlist: %s", domain)
+ }
+
+ // 2. Inject OTEL env vars into the workflow-level env: block.
+ otlpEnvLines := fmt.Sprintf(" OTEL_EXPORTER_OTLP_ENDPOINT: %s\n OTEL_SERVICE_NAME: gh-aw", endpoint)
+ if workflowData.Env == "" {
+ workflowData.Env = "env:\n" + otlpEnvLines
+ } else {
+ workflowData.Env = workflowData.Env + "\n" + otlpEnvLines
+ }
+ otlpLog.Printf("Injected OTEL env vars into workflow env block")
+}
diff --git a/pkg/workflow/observability_otlp_test.go b/pkg/workflow/observability_otlp_test.go
new file mode 100644
index 00000000000..fbdc52931cc
--- /dev/null
+++ b/pkg/workflow/observability_otlp_test.go
@@ -0,0 +1,332 @@
+//go:build !integration
+
+package workflow
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// TestExtractOTLPEndpointDomain verifies hostname extraction from OTLP endpoint URLs.
+func TestExtractOTLPEndpointDomain(t *testing.T) {
+ tests := []struct {
+ name string
+ endpoint string
+ expected string
+ }{
+ {
+ name: "empty endpoint returns empty string",
+ endpoint: "",
+ expected: "",
+ },
+ {
+ name: "GitHub Actions expression returns empty string",
+ endpoint: "${{ secrets.OTLP_ENDPOINT }}",
+ expected: "",
+ },
+ {
+ name: "inline expression returns empty string",
+ endpoint: "https://${{ secrets.HOST }}:4317",
+ expected: "",
+ },
+ {
+ name: "HTTPS URL without port",
+ endpoint: "https://traces.example.com",
+ expected: "traces.example.com",
+ },
+ {
+ name: "HTTPS URL with port",
+ endpoint: "https://traces.example.com:4317",
+ expected: "traces.example.com",
+ },
+ {
+ name: "HTTP URL with path",
+ endpoint: "http://otel-collector.internal:4318/v1/traces",
+ expected: "otel-collector.internal",
+ },
+ {
+ name: "gRPC URL",
+ endpoint: "grpc://traces.example.com:4317",
+ expected: "traces.example.com",
+ },
+ {
+ name: "subdomain",
+ endpoint: "https://otel.collector.corp.example.com:4317",
+ expected: "otel.collector.corp.example.com",
+ },
+ {
+ name: "invalid URL (no scheme) returns empty string",
+ endpoint: "traces.example.com:4317",
+ expected: "",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := extractOTLPEndpointDomain(tt.endpoint)
+ assert.Equal(t, tt.expected, got, "extractOTLPEndpointDomain(%q)", tt.endpoint)
+ })
+ }
+}
+
+// TestGetOTLPEndpointEnvValue verifies endpoint value extraction from FrontmatterConfig.
+func TestGetOTLPEndpointEnvValue(t *testing.T) {
+ tests := []struct {
+ name string
+ config *FrontmatterConfig
+ expected string
+ }{
+ {
+ name: "nil config returns empty string",
+ config: nil,
+ expected: "",
+ },
+ {
+ name: "nil observability returns empty string",
+ config: &FrontmatterConfig{},
+ expected: "",
+ },
+ {
+ name: "nil OTLP returns empty string",
+ config: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{},
+ },
+ expected: "",
+ },
+ {
+ name: "empty endpoint returns empty string",
+ config: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{Endpoint: ""},
+ },
+ },
+ expected: "",
+ },
+ {
+ name: "static URL endpoint",
+ config: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{Endpoint: "https://traces.example.com:4317"},
+ },
+ },
+ expected: "https://traces.example.com:4317",
+ },
+ {
+ name: "secret expression endpoint",
+ config: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{Endpoint: "${{ secrets.OTLP_ENDPOINT }}"},
+ },
+ },
+ expected: "${{ secrets.OTLP_ENDPOINT }}",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := getOTLPEndpointEnvValue(tt.config)
+ assert.Equal(t, tt.expected, got, "getOTLPEndpointEnvValue")
+ })
+ }
+}
+
+// TestInjectOTLPConfig verifies that injectOTLPConfig correctly modifies WorkflowData.
+func TestInjectOTLPConfig(t *testing.T) {
+ newCompiler := func() *Compiler { return &Compiler{} }
+
+ t.Run("no-op when OTLP is not configured", func(t *testing.T) {
+ c := newCompiler()
+ wd := &WorkflowData{
+ ParsedFrontmatter: &FrontmatterConfig{},
+ }
+ c.injectOTLPConfig(wd)
+ assert.Nil(t, wd.NetworkPermissions, "NetworkPermissions should remain nil")
+ assert.Empty(t, wd.Env, "Env should remain empty")
+ })
+
+ t.Run("no-op when ParsedFrontmatter is nil", func(t *testing.T) {
+ c := newCompiler()
+ wd := &WorkflowData{}
+ c.injectOTLPConfig(wd)
+ assert.Nil(t, wd.NetworkPermissions, "NetworkPermissions should remain nil")
+ assert.Empty(t, wd.Env, "Env should remain empty")
+ })
+
+ t.Run("injects env vars when endpoint is a secret expression", func(t *testing.T) {
+ c := newCompiler()
+ wd := &WorkflowData{
+ ParsedFrontmatter: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{Endpoint: "${{ secrets.OTLP_ENDPOINT }}"},
+ },
+ },
+ }
+ c.injectOTLPConfig(wd)
+
+ // NetworkPermissions.Allowed should NOT be populated (can't resolve expression)
+ if wd.NetworkPermissions != nil {
+ assert.Empty(t, wd.NetworkPermissions.Allowed, "Allowed should be empty for expression endpoints")
+ }
+
+ // Env should contain the OTEL vars
+ require.NotEmpty(t, wd.Env, "Env should be set")
+ assert.Contains(t, wd.Env, "OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTLP_ENDPOINT }}", "should contain endpoint var")
+ assert.Contains(t, wd.Env, "OTEL_SERVICE_NAME: gh-aw", "should contain service name")
+ })
+
+ t.Run("adds domain to new NetworkPermissions and injects env vars for static URL", func(t *testing.T) {
+ c := newCompiler()
+ wd := &WorkflowData{
+ ParsedFrontmatter: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{Endpoint: "https://traces.example.com:4317"},
+ },
+ },
+ }
+ c.injectOTLPConfig(wd)
+
+ require.NotNil(t, wd.NetworkPermissions, "NetworkPermissions should be created")
+ assert.Contains(t, wd.NetworkPermissions.Allowed, "traces.example.com", "should contain OTLP domain")
+
+ require.NotEmpty(t, wd.Env, "Env should be set")
+ assert.Contains(t, wd.Env, "OTEL_EXPORTER_OTLP_ENDPOINT: https://traces.example.com:4317")
+ assert.Contains(t, wd.Env, "OTEL_SERVICE_NAME: gh-aw")
+ assert.True(t, strings.HasPrefix(wd.Env, "env:"), "Env should start with 'env:'")
+ })
+
+ t.Run("appends domain to existing NetworkPermissions.Allowed", func(t *testing.T) {
+ c := newCompiler()
+ wd := &WorkflowData{
+ ParsedFrontmatter: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{Endpoint: "https://traces.example.com:4317"},
+ },
+ },
+ NetworkPermissions: &NetworkPermissions{
+ Allowed: []string{"api.github.com", "pypi.org"},
+ },
+ }
+ c.injectOTLPConfig(wd)
+
+ assert.Contains(t, wd.NetworkPermissions.Allowed, "api.github.com", "existing domains should remain")
+ assert.Contains(t, wd.NetworkPermissions.Allowed, "pypi.org", "existing domains should remain")
+ assert.Contains(t, wd.NetworkPermissions.Allowed, "traces.example.com", "OTLP domain should be appended")
+ })
+
+ t.Run("appends OTEL vars to existing Env block", func(t *testing.T) {
+ c := newCompiler()
+ wd := &WorkflowData{
+ ParsedFrontmatter: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{Endpoint: "https://traces.example.com"},
+ },
+ },
+ Env: "env:\n MY_VAR: hello",
+ }
+ c.injectOTLPConfig(wd)
+
+ assert.Contains(t, wd.Env, "MY_VAR: hello", "existing env var should remain")
+ assert.Contains(t, wd.Env, "OTEL_EXPORTER_OTLP_ENDPOINT: https://traces.example.com")
+ assert.Contains(t, wd.Env, "OTEL_SERVICE_NAME: gh-aw")
+ // Should still be a single env: block
+ assert.Equal(t, 1, strings.Count(wd.Env, "env:"), "should have exactly one env: key")
+ })
+
+ t.Run("OTEL_SERVICE_NAME is always gh-aw", func(t *testing.T) {
+ c := newCompiler()
+ wd := &WorkflowData{
+ ParsedFrontmatter: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{Endpoint: "https://otel.corp.com"},
+ },
+ },
+ }
+ c.injectOTLPConfig(wd)
+ assert.Contains(t, wd.Env, "OTEL_SERVICE_NAME: gh-aw", "service name should always be gh-aw")
+ })
+}
+
+// TestObservabilityConfigParsing verifies that the OTLPConfig is correctly parsed
+// from raw frontmatter via ParseFrontmatterConfig.
+func TestObservabilityConfigParsing(t *testing.T) {
+ tests := []struct {
+ name string
+ frontmatter map[string]any
+ wantOTLPConfig bool
+ expectedEndpoint string
+ }{
+ {
+ name: "no observability section",
+ frontmatter: map[string]any{},
+ wantOTLPConfig: false,
+ },
+ {
+ name: "observability without otlp",
+ frontmatter: map[string]any{
+ "observability": map[string]any{
+ "job-summary": "on",
+ },
+ },
+ wantOTLPConfig: false,
+ },
+ {
+ name: "observability with otlp endpoint",
+ frontmatter: map[string]any{
+ "observability": map[string]any{
+ "otlp": map[string]any{
+ "endpoint": "https://traces.example.com:4317",
+ },
+ },
+ },
+ wantOTLPConfig: true,
+ expectedEndpoint: "https://traces.example.com:4317",
+ },
+ {
+ name: "observability with otlp secret expression",
+ frontmatter: map[string]any{
+ "observability": map[string]any{
+ "otlp": map[string]any{
+ "endpoint": "${{ secrets.OTLP_ENDPOINT }}",
+ },
+ },
+ },
+ wantOTLPConfig: true,
+ expectedEndpoint: "${{ secrets.OTLP_ENDPOINT }}",
+ },
+ {
+ name: "observability with both job-summary and otlp",
+ frontmatter: map[string]any{
+ "observability": map[string]any{
+ "job-summary": "on",
+ "otlp": map[string]any{
+ "endpoint": "https://traces.example.com",
+ },
+ },
+ },
+ wantOTLPConfig: true,
+ expectedEndpoint: "https://traces.example.com",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ config, err := ParseFrontmatterConfig(tt.frontmatter)
+ require.NoError(t, err, "ParseFrontmatterConfig should not fail")
+ require.NotNil(t, config, "Config should not be nil")
+
+ if !tt.wantOTLPConfig {
+ if config.Observability != nil {
+ assert.Nil(t, config.Observability.OTLP, "OTLP should be nil")
+ }
+ return
+ }
+
+ require.NotNil(t, config.Observability, "Observability should not be nil")
+ require.NotNil(t, config.Observability.OTLP, "OTLP should not be nil")
+ assert.Equal(t, tt.expectedEndpoint, config.Observability.OTLP.Endpoint, "Endpoint should match")
+ })
+ }
+}
From 233b74c4cba94b60664a35b69cc02a3d13860636 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 06:08:39 +0000
Subject: [PATCH 03/16] feat: add send_otlp_span.cjs and instrument action
setup with job-name input
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/5738fc76-45bf-47ab-af6c-8de1dc9ec689
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/action.yml | 4 +
actions/setup/index.js | 15 ++
actions/setup/js/send_otlp_span.cjs | 218 ++++++++++++++++++
actions/setup/js/send_otlp_span.test.cjs | 280 +++++++++++++++++++++++
4 files changed, 517 insertions(+)
create mode 100644 actions/setup/js/send_otlp_span.cjs
create mode 100644 actions/setup/js/send_otlp_span.test.cjs
diff --git a/actions/setup/action.yml b/actions/setup/action.yml
index a03aabb6296..f93f57767ab 100644
--- a/actions/setup/action.yml
+++ b/actions/setup/action.yml
@@ -10,6 +10,10 @@ inputs:
description: 'Install @actions/github for handlers that use a per-handler github-token (creates Octokit via getOctokit)'
required: false
default: 'false'
+ job-name:
+ description: 'Name of the job being set up. When OTEL_EXPORTER_OTLP_ENDPOINT is configured, a gh-aw.job.setup span is pushed to the OTLP endpoint.'
+ required: false
+ default: ''
outputs:
files_copied:
diff --git a/actions/setup/index.js b/actions/setup/index.js
index cda1a0cd265..bf332757927 100644
--- a/actions/setup/index.js
+++ b/actions/setup/index.js
@@ -4,6 +4,9 @@
const { spawnSync } = require("child_process");
const path = require("path");
+// Record start time for the OTLP span before any setup work begins.
+const setupStartMs = Date.now();
+
// GitHub Actions sets INPUT_* env vars for JavaScript actions by converting
// input names to uppercase and replacing hyphens with underscores. Explicitly
// normalise the safe-output-custom-tokens input to ensure setup.sh finds it.
@@ -27,3 +30,15 @@ if (result.error) {
if (result.status !== 0) {
process.exit(result.status ?? 1);
}
+
+// Send a gh-aw.job.setup span to the OTLP endpoint when configured.
+// This is intentionally fire-and-forget with error suppression: trace export
+// failures must never break the workflow.
+(async () => {
+ try {
+ const { sendJobSetupSpan } = require(path.join(__dirname, "js", "send_otlp_span.cjs"));
+ await sendJobSetupSpan({ startMs: setupStartMs });
+ } catch {
+ // Non-fatal: silently ignore any OTLP export errors.
+ }
+})();
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
new file mode 100644
index 00000000000..8bc0cff58a2
--- /dev/null
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -0,0 +1,218 @@
+// @ts-check
+///
+
+const { randomBytes } = require("crypto");
+
+/**
+ * send_otlp_span.cjs
+ *
+ * Sends a single OTLP (OpenTelemetry Protocol) trace span to the configured
+ * HTTP/JSON endpoint. Used by actions/setup to instrument each job execution
+ * with basic telemetry.
+ *
+ * Design constraints:
+ * - No-op when OTEL_EXPORTER_OTLP_ENDPOINT is not set (zero overhead).
+ * - Errors are non-fatal: export failures must never break the workflow.
+ * - No third-party dependencies: uses only Node built-ins + native fetch.
+ */
+
+// ---------------------------------------------------------------------------
+// Low-level helpers
+// ---------------------------------------------------------------------------
+
+/**
+ * Generate a random 16-byte trace ID encoded as a 32-character hex string.
+ * @returns {string}
+ */
+function generateTraceId() {
+ return randomBytes(16).toString("hex");
+}
+
+/**
+ * Generate a random 8-byte span ID encoded as a 16-character hex string.
+ * @returns {string}
+ */
+function generateSpanId() {
+ return randomBytes(8).toString("hex");
+}
+
+/**
+ * Convert a Unix timestamp in milliseconds to a nanosecond string suitable for
+ * OTLP's `startTimeUnixNano` / `endTimeUnixNano` fields.
+ *
+ * BigInt arithmetic avoids floating-point precision loss for large timestamps.
+ *
+ * @param {number} ms - milliseconds since Unix epoch
+ * @returns {string} nanoseconds since Unix epoch as a decimal string
+ */
+function toNanoString(ms) {
+ return (BigInt(Math.floor(ms)) * 1_000_000n).toString();
+}
+
+/**
+ * Build a single OTLP attribute object in the key-value format expected by the
+ * OTLP/HTTP JSON wire format.
+ *
+ * @param {string} key
+ * @param {string | number | boolean} value
+ * @returns {{ key: string, value: object }}
+ */
+function buildAttr(key, value) {
+ if (typeof value === "boolean") {
+ return { key, value: { boolValue: value } };
+ }
+ if (typeof value === "number") {
+ return { key, value: { intValue: value } };
+ }
+ return { key, value: { stringValue: String(value) } };
+}
+
+// ---------------------------------------------------------------------------
+// OTLP payload builder
+// ---------------------------------------------------------------------------
+
+/**
+ * @typedef {Object} OTLPSpanOptions
+ * @property {string} traceId - 32-char hex trace ID
+ * @property {string} spanId - 16-char hex span ID
+ * @property {string} spanName - Human-readable span name
+ * @property {number} startMs - Span start time (ms since epoch)
+ * @property {number} endMs - Span end time (ms since epoch)
+ * @property {string} serviceName - Value for the service.name resource attribute
+ * @property {Array<{key: string, value: object}>} attributes - Span attributes
+ */
+
+/**
+ * Build an OTLP/HTTP JSON traces payload wrapping a single span.
+ *
+ * @param {OTLPSpanOptions} opts
+ * @returns {object} - Ready to be serialised as JSON and POSTed to `/v1/traces`
+ */
+function buildOTLPPayload({ traceId, spanId, spanName, startMs, endMs, serviceName, attributes }) {
+ return {
+ resourceSpans: [
+ {
+ resource: {
+ attributes: [buildAttr("service.name", serviceName)],
+ },
+ scopeSpans: [
+ {
+ scope: { name: "gh-aw.setup", version: "1.0.0" },
+ spans: [
+ {
+ traceId,
+ spanId,
+ name: spanName,
+ kind: 2, // SPAN_KIND_SERVER
+ startTimeUnixNano: toNanoString(startMs),
+ endTimeUnixNano: toNanoString(endMs),
+ status: { code: 1 }, // STATUS_CODE_OK
+ attributes,
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ };
+}
+
+// ---------------------------------------------------------------------------
+// HTTP transport
+// ---------------------------------------------------------------------------
+
+/**
+ * POST an OTLP traces payload to `{endpoint}/v1/traces`.
+ *
+ * @param {string} endpoint - OTLP base URL (e.g. https://traces.example.com:4317)
+ * @param {object} payload - Serialisable OTLP JSON object
+ * @returns {Promise}
+ * @throws {Error} when the server returns a non-2xx status
+ */
+async function sendOTLPSpan(endpoint, payload) {
+ const url = endpoint.replace(/\/$/, "") + "/v1/traces";
+ const response = await fetch(url, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload),
+ });
+ if (!response.ok) {
+ throw new Error(`OTLP export failed: HTTP ${response.status} ${response.statusText}`);
+ }
+}
+
+// ---------------------------------------------------------------------------
+// High-level: job setup span
+// ---------------------------------------------------------------------------
+
+/**
+ * @typedef {Object} SendJobSetupSpanOptions
+ * @property {number} [startMs] - Override for the span start time (ms). Defaults to `Date.now()`.
+ */
+
+/**
+ * Send a `gh-aw.job.setup` span to the configured OTLP endpoint.
+ *
+ * This is designed to be called from `actions/setup/index.js` immediately after
+ * the setup script completes. It is a no-op when `OTEL_EXPORTER_OTLP_ENDPOINT`
+ * is not set, and errors are swallowed so the workflow is never broken by tracing
+ * failures.
+ *
+ * Environment variables consumed:
+ * - `OTEL_EXPORTER_OTLP_ENDPOINT` – collector endpoint (required to send anything)
+ * - `OTEL_SERVICE_NAME` – service name (defaults to "gh-aw")
+ * - `INPUT_JOB_NAME` – job name passed via the `job-name` action input
+ * - `GH_AW_INFO_WORKFLOW_NAME` – workflow name injected by the gh-aw compiler
+ * - `GH_AW_INFO_ENGINE_ID` – engine ID injected by the gh-aw compiler
+ * - `GITHUB_RUN_ID` – GitHub Actions run ID
+ * - `GITHUB_ACTOR` – GitHub Actions actor (user / bot)
+ * - `GITHUB_REPOSITORY` – `owner/repo` string
+ *
+ * @param {SendJobSetupSpanOptions} [options]
+ * @returns {Promise}
+ */
+async function sendJobSetupSpan(options = {}) {
+ const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "";
+ if (!endpoint) {
+ return;
+ }
+
+ const startMs = options.startMs ?? Date.now();
+ const endMs = Date.now();
+
+ const serviceName = process.env.OTEL_SERVICE_NAME || "gh-aw";
+ const jobName = process.env.INPUT_JOB_NAME || "";
+ const workflowName = process.env.GH_AW_INFO_WORKFLOW_NAME || process.env.GITHUB_WORKFLOW || "";
+ const engineId = process.env.GH_AW_INFO_ENGINE_ID || "";
+ const runId = process.env.GITHUB_RUN_ID || "";
+ const actor = process.env.GITHUB_ACTOR || "";
+ const repository = process.env.GITHUB_REPOSITORY || "";
+
+ const attributes = [buildAttr("gh-aw.job.name", jobName), buildAttr("gh-aw.workflow.name", workflowName), buildAttr("gh-aw.run.id", runId), buildAttr("gh-aw.run.actor", actor), buildAttr("gh-aw.repository", repository)];
+
+ if (engineId) {
+ attributes.push(buildAttr("gh-aw.engine.id", engineId));
+ }
+
+ const payload = buildOTLPPayload({
+ traceId: generateTraceId(),
+ spanId: generateSpanId(),
+ spanName: "gh-aw.job.setup",
+ startMs,
+ endMs,
+ serviceName,
+ attributes,
+ });
+
+ await sendOTLPSpan(endpoint, payload);
+}
+
+module.exports = {
+ generateTraceId,
+ generateSpanId,
+ toNanoString,
+ buildAttr,
+ buildOTLPPayload,
+ sendOTLPSpan,
+ sendJobSetupSpan,
+};
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
new file mode 100644
index 00000000000..84c8549d989
--- /dev/null
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -0,0 +1,280 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+
+// ---------------------------------------------------------------------------
+// Module import
+// ---------------------------------------------------------------------------
+
+const { generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, sendOTLPSpan, sendJobSetupSpan } = await import("./send_otlp_span.cjs");
+
+// ---------------------------------------------------------------------------
+// generateTraceId
+// ---------------------------------------------------------------------------
+
+describe("generateTraceId", () => {
+ it("returns a 32-character hex string", () => {
+ const id = generateTraceId();
+ expect(id).toMatch(/^[0-9a-f]{32}$/);
+ });
+
+ it("returns a unique value on each call", () => {
+ expect(generateTraceId()).not.toBe(generateTraceId());
+ });
+});
+
+// ---------------------------------------------------------------------------
+// generateSpanId
+// ---------------------------------------------------------------------------
+
+describe("generateSpanId", () => {
+ it("returns a 16-character hex string", () => {
+ const id = generateSpanId();
+ expect(id).toMatch(/^[0-9a-f]{16}$/);
+ });
+
+ it("returns a unique value on each call", () => {
+ expect(generateSpanId()).not.toBe(generateSpanId());
+ });
+});
+
+// ---------------------------------------------------------------------------
+// toNanoString
+// ---------------------------------------------------------------------------
+
+describe("toNanoString", () => {
+ it("converts milliseconds to nanoseconds string", () => {
+ expect(toNanoString(1000)).toBe("1000000000");
+ });
+
+ it("handles zero", () => {
+ expect(toNanoString(0)).toBe("0");
+ });
+
+ it("handles a realistic GitHub Actions timestamp without precision loss", () => {
+ const ms = 1700000000000; // 2023-11-14T22:13:20Z
+ const nanos = toNanoString(ms);
+ expect(nanos).toBe("1700000000000000000");
+ });
+
+ it("truncates fractional milliseconds", () => {
+ // 1500.9 ms should truncate to 1500
+ expect(toNanoString(1500.9)).toBe("1500000000");
+ });
+});
+
+// ---------------------------------------------------------------------------
+// buildAttr
+// ---------------------------------------------------------------------------
+
+describe("buildAttr", () => {
+ it("returns stringValue for string input", () => {
+ expect(buildAttr("k", "v")).toEqual({ key: "k", value: { stringValue: "v" } });
+ });
+
+ it("returns intValue for number input", () => {
+ expect(buildAttr("k", 42)).toEqual({ key: "k", value: { intValue: 42 } });
+ });
+
+ it("returns boolValue for boolean input", () => {
+ expect(buildAttr("k", true)).toEqual({ key: "k", value: { boolValue: true } });
+ expect(buildAttr("k", false)).toEqual({ key: "k", value: { boolValue: false } });
+ });
+
+ it("coerces non-string non-number non-boolean to stringValue", () => {
+ // @ts-expect-error intentional type violation for coverage
+ expect(buildAttr("k", null).value).toHaveProperty("stringValue");
+ });
+});
+
+// ---------------------------------------------------------------------------
+// buildOTLPPayload
+// ---------------------------------------------------------------------------
+
+describe("buildOTLPPayload", () => {
+ it("produces a valid OTLP resourceSpans structure", () => {
+ const traceId = "a".repeat(32);
+ const spanId = "b".repeat(16);
+ const payload = buildOTLPPayload({
+ traceId,
+ spanId,
+ spanName: "gh-aw.job.setup",
+ startMs: 1000,
+ endMs: 2000,
+ serviceName: "gh-aw",
+ attributes: [buildAttr("foo", "bar")],
+ });
+
+ expect(payload.resourceSpans).toHaveLength(1);
+ const rs = payload.resourceSpans[0];
+
+ // Resource
+ expect(rs.resource.attributes).toContainEqual({ key: "service.name", value: { stringValue: "gh-aw" } });
+
+ // Scope
+ expect(rs.scopeSpans).toHaveLength(1);
+ expect(rs.scopeSpans[0].scope.name).toBe("gh-aw.setup");
+
+ // Span
+ const span = rs.scopeSpans[0].spans[0];
+ expect(span.traceId).toBe(traceId);
+ expect(span.spanId).toBe(spanId);
+ expect(span.name).toBe("gh-aw.job.setup");
+ expect(span.kind).toBe(2);
+ expect(span.startTimeUnixNano).toBe(toNanoString(1000));
+ expect(span.endTimeUnixNano).toBe(toNanoString(2000));
+ expect(span.status.code).toBe(1);
+ expect(span.attributes).toContainEqual({ key: "foo", value: { stringValue: "bar" } });
+ });
+});
+
+// ---------------------------------------------------------------------------
+// sendOTLPSpan
+// ---------------------------------------------------------------------------
+
+describe("sendOTLPSpan", () => {
+ beforeEach(() => {
+ vi.stubGlobal("fetch", vi.fn());
+ });
+
+ afterEach(() => {
+ vi.unstubAllGlobals();
+ });
+
+ it("POSTs JSON payload to endpoint/v1/traces", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ const payload = { resourceSpans: [] };
+ await sendOTLPSpan("https://traces.example.com:4317", payload);
+
+ expect(mockFetch).toHaveBeenCalledOnce();
+ const [url, init] = mockFetch.mock.calls[0];
+ expect(url).toBe("https://traces.example.com:4317/v1/traces");
+ expect(init.method).toBe("POST");
+ expect(init.headers["Content-Type"]).toBe("application/json");
+ expect(JSON.parse(init.body)).toEqual(payload);
+ });
+
+ it("strips trailing slash from endpoint before appending /v1/traces", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ await sendOTLPSpan("https://traces.example.com/", {});
+ const [url] = mockFetch.mock.calls[0];
+ expect(url).toBe("https://traces.example.com/v1/traces");
+ });
+
+ it("throws when server returns non-2xx status", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: false, status: 400, statusText: "Bad Request" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ await expect(sendOTLPSpan("https://traces.example.com", {})).rejects.toThrow("OTLP export failed: HTTP 400 Bad Request");
+ });
+});
+
+// ---------------------------------------------------------------------------
+// sendJobSetupSpan
+// ---------------------------------------------------------------------------
+
+describe("sendJobSetupSpan", () => {
+ const savedEnv = {};
+ const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "INPUT_JOB_NAME", "GH_AW_INFO_WORKFLOW_NAME", "GH_AW_INFO_ENGINE_ID", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
+
+ beforeEach(() => {
+ vi.stubGlobal("fetch", vi.fn());
+ for (const k of envKeys) {
+ savedEnv[k] = process.env[k];
+ delete process.env[k];
+ }
+ });
+
+ afterEach(() => {
+ vi.unstubAllGlobals();
+ for (const k of envKeys) {
+ if (savedEnv[k] !== undefined) {
+ process.env[k] = savedEnv[k];
+ } else {
+ delete process.env[k];
+ }
+ }
+ });
+
+ it("is a no-op when OTEL_EXPORTER_OTLP_ENDPOINT is not set", async () => {
+ await sendJobSetupSpan();
+ expect(fetch).not.toHaveBeenCalled();
+ });
+
+ it("sends a span when endpoint is configured", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ process.env.INPUT_JOB_NAME = "agent";
+ process.env.GH_AW_INFO_WORKFLOW_NAME = "my-workflow";
+ process.env.GH_AW_INFO_ENGINE_ID = "copilot";
+ process.env.GITHUB_RUN_ID = "123456789";
+ process.env.GITHUB_ACTOR = "octocat";
+ process.env.GITHUB_REPOSITORY = "owner/repo";
+
+ await sendJobSetupSpan();
+
+ expect(mockFetch).toHaveBeenCalledOnce();
+ const [url, init] = mockFetch.mock.calls[0];
+ expect(url).toBe("https://traces.example.com/v1/traces");
+ expect(init.method).toBe("POST");
+
+ const body = JSON.parse(init.body);
+ const span = body.resourceSpans[0].scopeSpans[0].spans[0];
+ expect(span.name).toBe("gh-aw.job.setup");
+ expect(span.traceId).toMatch(/^[0-9a-f]{32}$/);
+ expect(span.spanId).toMatch(/^[0-9a-f]{16}$/);
+
+ const attrs = Object.fromEntries(span.attributes.map(a => [a.key, a.value.stringValue ?? a.value.intValue ?? a.value.boolValue]));
+ expect(attrs["gh-aw.job.name"]).toBe("agent");
+ expect(attrs["gh-aw.workflow.name"]).toBe("my-workflow");
+ expect(attrs["gh-aw.engine.id"]).toBe("copilot");
+ expect(attrs["gh-aw.run.id"]).toBe("123456789");
+ expect(attrs["gh-aw.run.actor"]).toBe("octocat");
+ expect(attrs["gh-aw.repository"]).toBe("owner/repo");
+ });
+
+ it("uses the provided startMs for the span start time", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ const startMs = 1_700_000_000_000;
+ await sendJobSetupSpan({ startMs });
+
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ const span = body.resourceSpans[0].scopeSpans[0].spans[0];
+ expect(span.startTimeUnixNano).toBe(toNanoString(startMs));
+ });
+
+ it("uses OTEL_SERVICE_NAME for the resource service.name attribute", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ process.env.OTEL_SERVICE_NAME = "my-service";
+
+ await sendJobSetupSpan();
+
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ const resourceAttrs = body.resourceSpans[0].resource.attributes;
+ expect(resourceAttrs).toContainEqual({ key: "service.name", value: { stringValue: "my-service" } });
+ });
+
+ it("omits gh-aw.engine.id attribute when engine is not set", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+
+ await sendJobSetupSpan();
+
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ const span = body.resourceSpans[0].scopeSpans[0].spans[0];
+ const keys = span.attributes.map(a => a.key);
+ expect(keys).not.toContain("gh-aw.engine.id");
+ });
+});
From c890c5389838363b2935446b3062fd7e3e086eb9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 06:11:22 +0000
Subject: [PATCH 04/16] fix: address code review feedback on send_otlp_span.cjs
and test file
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/5738fc76-45bf-47ab-af6c-8de1dc9ec689
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/index.js | 6 ++++--
actions/setup/js/send_otlp_span.test.cjs | 17 ++++++++++++++++-
2 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/actions/setup/index.js b/actions/setup/index.js
index bf332757927..eeaab29b59a 100644
--- a/actions/setup/index.js
+++ b/actions/setup/index.js
@@ -32,8 +32,10 @@ if (result.status !== 0) {
}
// Send a gh-aw.job.setup span to the OTLP endpoint when configured.
-// This is intentionally fire-and-forget with error suppression: trace export
-// failures must never break the workflow.
+// The IIFE returns a Promise that keeps the Node.js event loop alive until
+// the fetch request completes, so the span is delivered before the process
+// exits naturally. Errors are swallowed: trace export failures must never
+// break the workflow.
(async () => {
try {
const { sendJobSetupSpan } = require(path.join(__dirname, "js", "send_otlp_span.cjs"));
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index 84c8549d989..11b359855bc 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -176,6 +176,7 @@ describe("sendOTLPSpan", () => {
// ---------------------------------------------------------------------------
describe("sendJobSetupSpan", () => {
+ /** @type {Record} */
const savedEnv = {};
const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "INPUT_JOB_NAME", "GH_AW_INFO_WORKFLOW_NAME", "GH_AW_INFO_ENGINE_ID", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
@@ -198,6 +199,20 @@ describe("sendJobSetupSpan", () => {
}
});
+ /**
+ * Extract the scalar value from an OTLP attribute's `value` union, covering all
+ * known OTLP value types (stringValue, intValue, boolValue).
+ *
+ * @param {{ key: string, value: { stringValue?: string, intValue?: number, boolValue?: boolean } }} attr
+ * @returns {string | number | boolean | undefined}
+ */
+ function attrValue(attr) {
+ if (attr.value.stringValue !== undefined) return attr.value.stringValue;
+ if (attr.value.intValue !== undefined) return attr.value.intValue;
+ if (attr.value.boolValue !== undefined) return attr.value.boolValue;
+ return undefined;
+ }
+
it("is a no-op when OTEL_EXPORTER_OTLP_ENDPOINT is not set", async () => {
await sendJobSetupSpan();
expect(fetch).not.toHaveBeenCalled();
@@ -228,7 +243,7 @@ describe("sendJobSetupSpan", () => {
expect(span.traceId).toMatch(/^[0-9a-f]{32}$/);
expect(span.spanId).toMatch(/^[0-9a-f]{16}$/);
- const attrs = Object.fromEntries(span.attributes.map(a => [a.key, a.value.stringValue ?? a.value.intValue ?? a.value.boolValue]));
+ const attrs = Object.fromEntries(span.attributes.map(a => [a.key, attrValue(a)]));
expect(attrs["gh-aw.job.name"]).toBe("agent");
expect(attrs["gh-aw.workflow.name"]).toBe("my-workflow");
expect(attrs["gh-aw.engine.id"]).toBe("copilot");
From ffd3965b8c8804c960edb65242f160a01e2b0e27 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 06:50:45 +0000
Subject: [PATCH 05/16] feat: add trace-id input/output to actions/setup for
cross-job span correlation
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/461b1d13-5dec-4bb7-8daa-d36d583465a4
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/action.yml | 6 +++
actions/setup/index.js | 11 +++-
actions/setup/js/send_otlp_span.cjs | 28 ++++++++---
actions/setup/js/send_otlp_span.test.cjs | 64 +++++++++++++++++++++---
4 files changed, 94 insertions(+), 15 deletions(-)
diff --git a/actions/setup/action.yml b/actions/setup/action.yml
index f93f57767ab..45cbbab4b89 100644
--- a/actions/setup/action.yml
+++ b/actions/setup/action.yml
@@ -14,10 +14,16 @@ inputs:
description: 'Name of the job being set up. When OTEL_EXPORTER_OTLP_ENDPOINT is configured, a gh-aw.job.setup span is pushed to the OTLP endpoint.'
required: false
default: ''
+ trace-id:
+ description: 'OTLP trace ID to reuse for cross-job span correlation. Pass the trace-id output of the activation job setup step to correlate all job spans under the same trace. When omitted a new trace ID is generated.'
+ required: false
+ default: ''
outputs:
files_copied:
description: 'Number of files copied'
+ trace-id:
+ description: 'The OTLP trace ID used for the gh-aw.job.setup span. Pass this to subsequent job setup steps via the trace-id input to correlate all job spans under a single trace.'
runs:
using: 'node24'
diff --git a/actions/setup/index.js b/actions/setup/index.js
index eeaab29b59a..ea873ecc647 100644
--- a/actions/setup/index.js
+++ b/actions/setup/index.js
@@ -38,9 +38,16 @@ if (result.status !== 0) {
// break the workflow.
(async () => {
try {
+ const { appendFileSync } = require("fs");
const { sendJobSetupSpan } = require(path.join(__dirname, "js", "send_otlp_span.cjs"));
- await sendJobSetupSpan({ startMs: setupStartMs });
+ const traceId = await sendJobSetupSpan({ startMs: setupStartMs });
+ // Always expose the trace ID as an action output so downstream jobs can
+ // reference it via `steps..outputs.trace-id` and pass it to their own
+ // setup steps to correlate all job spans under a single trace.
+ if (traceId && process.env.GITHUB_OUTPUT) {
+ appendFileSync(process.env.GITHUB_OUTPUT, `trace-id=${traceId}\n`);
+ }
} catch {
- // Non-fatal: silently ignore any OTLP export errors.
+ // Non-fatal: silently ignore any OTLP export or output-write errors.
}
})();
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
index 8bc0cff58a2..d9a963b5c1e 100644
--- a/actions/setup/js/send_otlp_span.cjs
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -147,21 +147,28 @@ async function sendOTLPSpan(endpoint, payload) {
/**
* @typedef {Object} SendJobSetupSpanOptions
- * @property {number} [startMs] - Override for the span start time (ms). Defaults to `Date.now()`.
+ * @property {number} [startMs] - Override for the span start time (ms). Defaults to `Date.now()`.
+ * @property {string} [traceId] - Existing trace ID to reuse for cross-job correlation.
+ * When omitted the value is taken from the `INPUT_TRACE_ID` environment variable (the
+ * `trace-id` action input); if that is also absent a new random trace ID is generated.
+ * Pass the `trace-id` output of the activation job's setup step to correlate all
+ * subsequent job spans under the same trace.
*/
/**
* Send a `gh-aw.job.setup` span to the configured OTLP endpoint.
*
* This is designed to be called from `actions/setup/index.js` immediately after
- * the setup script completes. It is a no-op when `OTEL_EXPORTER_OTLP_ENDPOINT`
- * is not set, and errors are swallowed so the workflow is never broken by tracing
- * failures.
+ * the setup script completes. It always returns the trace ID so callers can
+ * expose it as an action output for cross-job correlation — even when
+ * `OTEL_EXPORTER_OTLP_ENDPOINT` is not set (no span is sent in that case).
+ * Errors are swallowed so the workflow is never broken by tracing failures.
*
* Environment variables consumed:
* - `OTEL_EXPORTER_OTLP_ENDPOINT` – collector endpoint (required to send anything)
* - `OTEL_SERVICE_NAME` – service name (defaults to "gh-aw")
* - `INPUT_JOB_NAME` – job name passed via the `job-name` action input
+ * - `INPUT_TRACE_ID` – optional trace ID passed via the `trace-id` action input
* - `GH_AW_INFO_WORKFLOW_NAME` – workflow name injected by the gh-aw compiler
* - `GH_AW_INFO_ENGINE_ID` – engine ID injected by the gh-aw compiler
* - `GITHUB_RUN_ID` – GitHub Actions run ID
@@ -169,12 +176,18 @@ async function sendOTLPSpan(endpoint, payload) {
* - `GITHUB_REPOSITORY` – `owner/repo` string
*
* @param {SendJobSetupSpanOptions} [options]
- * @returns {Promise}
+ * @returns {Promise} The trace ID used for the span (generated or passed in).
*/
async function sendJobSetupSpan(options = {}) {
+ // Resolve the trace ID before the early-return so it is always available as
+ // an action output regardless of whether OTLP is configured.
+ // Priority: options.traceId > INPUT_TRACE_ID env var > newly generated ID.
+ const inputTraceId = (process.env.INPUT_TRACE_ID || "").trim();
+ const traceId = options.traceId || inputTraceId || generateTraceId();
+
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "";
if (!endpoint) {
- return;
+ return traceId;
}
const startMs = options.startMs ?? Date.now();
@@ -195,7 +208,7 @@ async function sendJobSetupSpan(options = {}) {
}
const payload = buildOTLPPayload({
- traceId: generateTraceId(),
+ traceId,
spanId: generateSpanId(),
spanName: "gh-aw.job.setup",
startMs,
@@ -205,6 +218,7 @@ async function sendJobSetupSpan(options = {}) {
});
await sendOTLPSpan(endpoint, payload);
+ return traceId;
}
module.exports = {
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index 11b359855bc..3bdec534a72 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -178,7 +178,7 @@ describe("sendOTLPSpan", () => {
describe("sendJobSetupSpan", () => {
/** @type {Record} */
const savedEnv = {};
- const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "INPUT_JOB_NAME", "GH_AW_INFO_WORKFLOW_NAME", "GH_AW_INFO_ENGINE_ID", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
+ const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "INPUT_JOB_NAME", "INPUT_TRACE_ID", "GH_AW_INFO_WORKFLOW_NAME", "GH_AW_INFO_ENGINE_ID", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
beforeEach(() => {
vi.stubGlobal("fetch", vi.fn());
@@ -213,12 +213,20 @@ describe("sendJobSetupSpan", () => {
return undefined;
}
- it("is a no-op when OTEL_EXPORTER_OTLP_ENDPOINT is not set", async () => {
- await sendJobSetupSpan();
+ it("returns a trace ID even when OTEL_EXPORTER_OTLP_ENDPOINT is not set", async () => {
+ const traceId = await sendJobSetupSpan();
+ expect(traceId).toMatch(/^[0-9a-f]{32}$/);
expect(fetch).not.toHaveBeenCalled();
});
- it("sends a span when endpoint is configured", async () => {
+ it("returns the same trace ID when called with INPUT_TRACE_ID and no endpoint", async () => {
+ process.env.INPUT_TRACE_ID = "a".repeat(32);
+ const traceId = await sendJobSetupSpan();
+ expect(traceId).toBe("a".repeat(32));
+ expect(fetch).not.toHaveBeenCalled();
+ });
+
+ it("sends a span when endpoint is configured and returns the trace ID", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
vi.stubGlobal("fetch", mockFetch);
@@ -230,8 +238,9 @@ describe("sendJobSetupSpan", () => {
process.env.GITHUB_ACTOR = "octocat";
process.env.GITHUB_REPOSITORY = "owner/repo";
- await sendJobSetupSpan();
+ const traceId = await sendJobSetupSpan();
+ expect(traceId).toMatch(/^[0-9a-f]{32}$/);
expect(mockFetch).toHaveBeenCalledOnce();
const [url, init] = mockFetch.mock.calls[0];
expect(url).toBe("https://traces.example.com/v1/traces");
@@ -240,7 +249,8 @@ describe("sendJobSetupSpan", () => {
const body = JSON.parse(init.body);
const span = body.resourceSpans[0].scopeSpans[0].spans[0];
expect(span.name).toBe("gh-aw.job.setup");
- expect(span.traceId).toMatch(/^[0-9a-f]{32}$/);
+ // Span traceId must match the returned value (cross-job correlation)
+ expect(span.traceId).toBe(traceId);
expect(span.spanId).toMatch(/^[0-9a-f]{16}$/);
const attrs = Object.fromEntries(span.attributes.map(a => [a.key, attrValue(a)]));
@@ -252,6 +262,48 @@ describe("sendJobSetupSpan", () => {
expect(attrs["gh-aw.repository"]).toBe("owner/repo");
});
+ it("uses trace ID from options.traceId for cross-job correlation", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ const correlationTraceId = "b".repeat(32);
+
+ const returned = await sendJobSetupSpan({ traceId: correlationTraceId });
+
+ expect(returned).toBe(correlationTraceId);
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ expect(body.resourceSpans[0].scopeSpans[0].spans[0].traceId).toBe(correlationTraceId);
+ });
+
+ it("uses trace ID from INPUT_TRACE_ID env var when options.traceId is absent", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ process.env.INPUT_TRACE_ID = "c".repeat(32);
+
+ const returned = await sendJobSetupSpan();
+
+ expect(returned).toBe("c".repeat(32));
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ expect(body.resourceSpans[0].scopeSpans[0].spans[0].traceId).toBe("c".repeat(32));
+ });
+
+ it("options.traceId takes priority over INPUT_TRACE_ID", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ process.env.INPUT_TRACE_ID = "d".repeat(32);
+
+ const returned = await sendJobSetupSpan({ traceId: "e".repeat(32) });
+
+ expect(returned).toBe("e".repeat(32));
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ expect(body.resourceSpans[0].scopeSpans[0].spans[0].traceId).toBe("e".repeat(32));
+ });
+
it("uses the provided startMs for the span start time", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
vi.stubGlobal("fetch", mockFetch);
From 6a3a6b90765ec9d8f409be6662ae207598fda18c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 06:54:06 +0000
Subject: [PATCH 06/16] fix: validate trace-id format, add isValidTraceId
helper + tests
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/461b1d13-5dec-4bb7-8daa-d36d583465a4
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/action.yml | 2 +-
actions/setup/index.js | 2 +-
actions/setup/js/send_otlp_span.cjs | 25 ++++++++++++++--
actions/setup/js/send_otlp_span.test.cjs | 37 +++++++++++++++++++++++-
4 files changed, 60 insertions(+), 6 deletions(-)
diff --git a/actions/setup/action.yml b/actions/setup/action.yml
index 45cbbab4b89..8f32cb2503c 100644
--- a/actions/setup/action.yml
+++ b/actions/setup/action.yml
@@ -15,7 +15,7 @@ inputs:
required: false
default: ''
trace-id:
- description: 'OTLP trace ID to reuse for cross-job span correlation. Pass the trace-id output of the activation job setup step to correlate all job spans under the same trace. When omitted a new trace ID is generated.'
+ description: 'OTLP trace ID (32-character hexadecimal string) to reuse for cross-job span correlation. Pass the trace-id output of the activation job setup step to correlate all job spans under the same trace. When omitted a new trace ID is generated.'
required: false
default: ''
diff --git a/actions/setup/index.js b/actions/setup/index.js
index ea873ecc647..4ff788d42e8 100644
--- a/actions/setup/index.js
+++ b/actions/setup/index.js
@@ -44,7 +44,7 @@ if (result.status !== 0) {
// Always expose the trace ID as an action output so downstream jobs can
// reference it via `steps..outputs.trace-id` and pass it to their own
// setup steps to correlate all job spans under a single trace.
- if (traceId && process.env.GITHUB_OUTPUT) {
+ if (/^[0-9a-f]{32}$/.test(traceId) && process.env.GITHUB_OUTPUT) {
appendFileSync(process.env.GITHUB_OUTPUT, `trace-id=${traceId}\n`);
}
} catch {
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
index d9a963b5c1e..f2bae3bc2da 100644
--- a/actions/setup/js/send_otlp_span.cjs
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -145,13 +145,28 @@ async function sendOTLPSpan(endpoint, payload) {
// High-level: job setup span
// ---------------------------------------------------------------------------
+/**
+ * Regular expression that matches a valid OTLP trace ID: 32 lowercase hex characters.
+ * @type {RegExp}
+ */
+const TRACE_ID_RE = /^[0-9a-f]{32}$/;
+
+/**
+ * Validate that a string is a well-formed OTLP trace ID (32 lowercase hex chars).
+ * @param {string} id
+ * @returns {boolean}
+ */
+function isValidTraceId(id) {
+ return TRACE_ID_RE.test(id);
+}
+
/**
* @typedef {Object} SendJobSetupSpanOptions
* @property {number} [startMs] - Override for the span start time (ms). Defaults to `Date.now()`.
* @property {string} [traceId] - Existing trace ID to reuse for cross-job correlation.
* When omitted the value is taken from the `INPUT_TRACE_ID` environment variable (the
* `trace-id` action input); if that is also absent a new random trace ID is generated.
- * Pass the `trace-id` output of the activation job's setup step to correlate all
+ * Pass the `trace-id` output of the activation job setup step to correlate all
* subsequent job spans under the same trace.
*/
@@ -182,8 +197,11 @@ async function sendJobSetupSpan(options = {}) {
// Resolve the trace ID before the early-return so it is always available as
// an action output regardless of whether OTLP is configured.
// Priority: options.traceId > INPUT_TRACE_ID env var > newly generated ID.
- const inputTraceId = (process.env.INPUT_TRACE_ID || "").trim();
- const traceId = options.traceId || inputTraceId || generateTraceId();
+ // Invalid (non-hex, wrong-length) values are silently discarded in favour of a new ID.
+ const rawInputTraceId = (process.env.INPUT_TRACE_ID || "").trim().toLowerCase();
+ const inputTraceId = isValidTraceId(rawInputTraceId) ? rawInputTraceId : "";
+ const candidateTraceId = options.traceId || inputTraceId;
+ const traceId = candidateTraceId && isValidTraceId(candidateTraceId) ? candidateTraceId : generateTraceId();
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "";
if (!endpoint) {
@@ -222,6 +240,7 @@ async function sendJobSetupSpan(options = {}) {
}
module.exports = {
+ isValidTraceId,
generateTraceId,
generateSpanId,
toNanoString,
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index 3bdec534a72..a277954a45b 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -4,7 +4,35 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
// Module import
// ---------------------------------------------------------------------------
-const { generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, sendOTLPSpan, sendJobSetupSpan } = await import("./send_otlp_span.cjs");
+const { isValidTraceId, generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, sendOTLPSpan, sendJobSetupSpan } = await import("./send_otlp_span.cjs");
+
+// ---------------------------------------------------------------------------
+// isValidTraceId
+// ---------------------------------------------------------------------------
+
+describe("isValidTraceId", () => {
+ it("accepts a valid 32-character lowercase hex trace ID", () => {
+ expect(isValidTraceId("a".repeat(32))).toBe(true);
+ expect(isValidTraceId("0123456789abcdef0123456789abcdef")).toBe(true);
+ });
+
+ it("rejects uppercase hex characters", () => {
+ expect(isValidTraceId("A".repeat(32))).toBe(false);
+ });
+
+ it("rejects strings that are too short or too long", () => {
+ expect(isValidTraceId("a".repeat(31))).toBe(false);
+ expect(isValidTraceId("a".repeat(33))).toBe(false);
+ });
+
+ it("rejects empty string", () => {
+ expect(isValidTraceId("")).toBe(false);
+ });
+
+ it("rejects non-hex characters", () => {
+ expect(isValidTraceId("z".repeat(32))).toBe(false);
+ });
+});
// ---------------------------------------------------------------------------
// generateTraceId
@@ -226,6 +254,13 @@ describe("sendJobSetupSpan", () => {
expect(fetch).not.toHaveBeenCalled();
});
+ it("generates a new trace ID when INPUT_TRACE_ID is invalid", async () => {
+ process.env.INPUT_TRACE_ID = "not-a-valid-trace-id";
+ const traceId = await sendJobSetupSpan();
+ expect(traceId).toMatch(/^[0-9a-f]{32}$/);
+ expect(traceId).not.toBe("not-a-valid-trace-id");
+ });
+
it("sends a span when endpoint is configured and returns the trace ID", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
vi.stubGlobal("fetch", mockFetch);
From 4a405219f2dcb420ef27b6e9bcfabf6cd0e0f085 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 06:56:21 +0000
Subject: [PATCH 07/16] fix: validate options.traceId, normalize uppercase
input, reuse isValidTraceId in index.js
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/461b1d13-5dec-4bb7-8daa-d36d583465a4
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/index.js | 4 ++--
actions/setup/js/send_otlp_span.cjs | 12 +++++++++---
actions/setup/js/send_otlp_span.test.cjs | 13 +++++++++++++
3 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/actions/setup/index.js b/actions/setup/index.js
index 4ff788d42e8..e71b8f47aff 100644
--- a/actions/setup/index.js
+++ b/actions/setup/index.js
@@ -39,12 +39,12 @@ if (result.status !== 0) {
(async () => {
try {
const { appendFileSync } = require("fs");
- const { sendJobSetupSpan } = require(path.join(__dirname, "js", "send_otlp_span.cjs"));
+ const { isValidTraceId, sendJobSetupSpan } = require(path.join(__dirname, "js", "send_otlp_span.cjs"));
const traceId = await sendJobSetupSpan({ startMs: setupStartMs });
// Always expose the trace ID as an action output so downstream jobs can
// reference it via `steps..outputs.trace-id` and pass it to their own
// setup steps to correlate all job spans under a single trace.
- if (/^[0-9a-f]{32}$/.test(traceId) && process.env.GITHUB_OUTPUT) {
+ if (isValidTraceId(traceId) && process.env.GITHUB_OUTPUT) {
appendFileSync(process.env.GITHUB_OUTPUT, `trace-id=${traceId}\n`);
}
} catch {
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
index f2bae3bc2da..1a75a9eb202 100644
--- a/actions/setup/js/send_otlp_span.cjs
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -197,11 +197,17 @@ async function sendJobSetupSpan(options = {}) {
// Resolve the trace ID before the early-return so it is always available as
// an action output regardless of whether OTLP is configured.
// Priority: options.traceId > INPUT_TRACE_ID env var > newly generated ID.
- // Invalid (non-hex, wrong-length) values are silently discarded in favour of a new ID.
+ // Invalid (wrong length, non-hex) values are silently discarded.
+
+ // Validate options.traceId if supplied; callers may pass raw user input.
+ const optionsTraceId = options.traceId && isValidTraceId(options.traceId) ? options.traceId : "";
+
+ // Normalise INPUT_TRACE_ID to lowercase before validating: OTLP requires lowercase
+ // hex, but trace IDs pasted from external tools may use uppercase characters.
const rawInputTraceId = (process.env.INPUT_TRACE_ID || "").trim().toLowerCase();
const inputTraceId = isValidTraceId(rawInputTraceId) ? rawInputTraceId : "";
- const candidateTraceId = options.traceId || inputTraceId;
- const traceId = candidateTraceId && isValidTraceId(candidateTraceId) ? candidateTraceId : generateTraceId();
+
+ const traceId = optionsTraceId || inputTraceId || generateTraceId();
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "";
if (!endpoint) {
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index a277954a45b..7853b1f653a 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -261,6 +261,19 @@ describe("sendJobSetupSpan", () => {
expect(traceId).not.toBe("not-a-valid-trace-id");
});
+ it("normalises uppercase INPUT_TRACE_ID to lowercase and accepts it", async () => {
+ // Trace IDs pasted from external tools may be uppercase; we normalise them.
+ process.env.INPUT_TRACE_ID = "A".repeat(32);
+ const traceId = await sendJobSetupSpan();
+ expect(traceId).toBe("a".repeat(32));
+ });
+
+ it("rejects an invalid options.traceId and generates a new trace ID", async () => {
+ const returned = await sendJobSetupSpan({ traceId: "too-short" });
+ expect(returned).toMatch(/^[0-9a-f]{32}$/);
+ expect(returned).not.toBe("too-short");
+ });
+
it("sends a span when endpoint is configured and returns the trace ID", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
vi.stubGlobal("fetch", mockFetch);
From 965d5d7414ba4dfe4cb9406b2e77019274f326db Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 07:28:01 +0000
Subject: [PATCH 08/16] feat: scope name gh-aw + version, retry/warn
sendOTLPSpan, conclusion spans for safe-outputs/conclusion jobs"
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/2a7e539d-2a7e-452d-8b26-8de15a7ebabe
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
.../agent-performance-analyzer.lock.yml | 16 ++
.../workflows/agent-persona-explorer.lock.yml | 16 ++
.../agentic-observability-kit.lock.yml | 16 ++
.github/workflows/ai-moderator.lock.yml | 16 ++
.github/workflows/archie.lock.yml | 16 ++
.github/workflows/artifacts-summary.lock.yml | 16 ++
.github/workflows/audit-workflows.lock.yml | 16 ++
.github/workflows/auto-triage-issues.lock.yml | 16 ++
.github/workflows/blog-auditor.lock.yml | 16 ++
.github/workflows/bot-detection.lock.yml | 16 ++
.github/workflows/brave.lock.yml | 16 ++
.../breaking-change-checker.lock.yml | 16 ++
.github/workflows/changeset.lock.yml | 16 ++
.github/workflows/ci-coach.lock.yml | 16 ++
.github/workflows/ci-doctor.lock.yml | 16 ++
.../claude-code-user-docs-review.lock.yml | 16 ++
.../workflows/claude-token-optimizer.lock.yml | 16 ++
.../claude-token-usage-analyzer.lock.yml | 16 ++
.../cli-consistency-checker.lock.yml | 16 ++
.../workflows/cli-version-checker.lock.yml | 16 ++
.github/workflows/cloclo.lock.yml | 16 ++
.../workflows/code-scanning-fixer.lock.yml | 16 ++
.github/workflows/code-simplifier.lock.yml | 16 ++
.../commit-changes-analyzer.lock.yml | 16 ++
.../constraint-solving-potd.lock.yml | 16 ++
.github/workflows/contribution-check.lock.yml | 16 ++
.../workflows/copilot-agent-analysis.lock.yml | 16 ++
.../copilot-cli-deep-research.lock.yml | 16 ++
.../copilot-pr-merged-report.lock.yml | 16 ++
.../copilot-pr-nlp-analysis.lock.yml | 16 ++
.../copilot-pr-prompt-analysis.lock.yml | 16 ++
.../copilot-session-insights.lock.yml | 16 ++
.../copilot-token-optimizer.lock.yml | 16 ++
.../copilot-token-usage-analyzer.lock.yml | 16 ++
.github/workflows/craft.lock.yml | 16 ++
.../daily-architecture-diagram.lock.yml | 16 ++
.../daily-assign-issue-to-user.lock.yml | 16 ++
.github/workflows/daily-choice-test.lock.yml | 16 ++
.../workflows/daily-cli-performance.lock.yml | 16 ++
.../workflows/daily-cli-tools-tester.lock.yml | 16 ++
.github/workflows/daily-code-metrics.lock.yml | 16 ++
.../daily-community-attribution.lock.yml | 16 ++
.../workflows/daily-compiler-quality.lock.yml | 16 ++
.../daily-copilot-token-report.lock.yml | 16 ++
.github/workflows/daily-doc-healer.lock.yml | 16 ++
.github/workflows/daily-doc-updater.lock.yml | 16 ++
.github/workflows/daily-fact.lock.yml | 16 ++
.github/workflows/daily-file-diet.lock.yml | 16 ++
.../workflows/daily-firewall-report.lock.yml | 16 ++
.../workflows/daily-function-namer.lock.yml | 16 ++
.../daily-integrity-analysis.lock.yml | 16 ++
.../workflows/daily-issues-report.lock.yml | 16 ++
.../daily-malicious-code-scan.lock.yml | 16 ++
.../daily-mcp-concurrency-analysis.lock.yml | 16 ++
.../daily-multi-device-docs-tester.lock.yml | 16 ++
.github/workflows/daily-news.lock.yml | 16 ++
.../daily-observability-report.lock.yml | 16 ++
.../daily-performance-summary.lock.yml | 16 ++
.github/workflows/daily-regulatory.lock.yml | 16 ++
.../daily-rendering-scripts-verifier.lock.yml | 16 ++
.../workflows/daily-repo-chronicle.lock.yml | 16 ++
.../daily-safe-output-integrator.lock.yml | 16 ++
.../daily-safe-output-optimizer.lock.yml | 16 ++
.../daily-safe-outputs-conformance.lock.yml | 16 ++
.../workflows/daily-secrets-analysis.lock.yml | 16 ++
.../daily-security-red-team.lock.yml | 16 ++
.github/workflows/daily-semgrep-scan.lock.yml | 16 ++
.../daily-syntax-error-quality.lock.yml | 16 ++
.../daily-team-evolution-insights.lock.yml | 16 ++
.github/workflows/daily-team-status.lock.yml | 16 ++
.../daily-testify-uber-super-expert.lock.yml | 16 ++
.../workflows/daily-workflow-updater.lock.yml | 16 ++
.github/workflows/dead-code-remover.lock.yml | 16 ++
.github/workflows/deep-report.lock.yml | 16 ++
.github/workflows/delight.lock.yml | 16 ++
.github/workflows/dependabot-burner.lock.yml | 16 ++
.../workflows/dependabot-go-checker.lock.yml | 16 ++
.github/workflows/dev-hawk.lock.yml | 16 ++
.github/workflows/dev.lock.yml | 16 ++
.../developer-docs-consolidator.lock.yml | 16 ++
.github/workflows/dictation-prompt.lock.yml | 16 ++
.../workflows/discussion-task-miner.lock.yml | 16 ++
.github/workflows/docs-noob-tester.lock.yml | 16 ++
.github/workflows/draft-pr-cleanup.lock.yml | 16 ++
.../duplicate-code-detector.lock.yml | 16 ++
.../example-workflow-analyzer.lock.yml | 16 ++
.github/workflows/firewall-escape.lock.yml | 16 ++
.../workflows/functional-pragmatist.lock.yml | 16 ++
.../github-mcp-structural-analysis.lock.yml | 16 ++
.../github-mcp-tools-report.lock.yml | 16 ++
.../github-remote-mcp-auth-test.lock.yml | 16 ++
.../workflows/glossary-maintainer.lock.yml | 16 ++
.github/workflows/go-fan.lock.yml | 16 ++
.github/workflows/go-logger.lock.yml | 16 ++
.../workflows/go-pattern-detector.lock.yml | 16 ++
.github/workflows/gpclean.lock.yml | 16 ++
.github/workflows/grumpy-reviewer.lock.yml | 16 ++
.github/workflows/hourly-ci-cleaner.lock.yml | 16 ++
.../workflows/instructions-janitor.lock.yml | 16 ++
.github/workflows/issue-arborist.lock.yml | 16 ++
.github/workflows/issue-monster.lock.yml | 16 ++
.github/workflows/issue-triage-agent.lock.yml | 16 ++
.github/workflows/jsweep.lock.yml | 16 ++
.../workflows/layout-spec-maintainer.lock.yml | 16 ++
.github/workflows/lockfile-stats.lock.yml | 16 ++
.github/workflows/mcp-inspector.lock.yml | 16 ++
.github/workflows/mergefest.lock.yml | 16 ++
.../workflows/notion-issue-summary.lock.yml | 16 ++
.github/workflows/org-health-report.lock.yml | 16 ++
.github/workflows/pdf-summary.lock.yml | 16 ++
.github/workflows/plan.lock.yml | 16 ++
.github/workflows/poem-bot.lock.yml | 16 ++
.github/workflows/portfolio-analyst.lock.yml | 16 ++
.../workflows/pr-nitpick-reviewer.lock.yml | 16 ++
.github/workflows/pr-triage-agent.lock.yml | 16 ++
.../prompt-clustering-analysis.lock.yml | 16 ++
.github/workflows/python-data-charts.lock.yml | 16 ++
.github/workflows/q.lock.yml | 16 ++
.github/workflows/refiner.lock.yml | 16 ++
.github/workflows/release.lock.yml | 16 ++
.../workflows/repo-audit-analyzer.lock.yml | 16 ++
.github/workflows/repo-tree-map.lock.yml | 16 ++
.../repository-quality-improver.lock.yml | 16 ++
.github/workflows/research.lock.yml | 16 ++
.github/workflows/safe-output-health.lock.yml | 16 ++
.../schema-consistency-checker.lock.yml | 16 ++
.../schema-feature-coverage.lock.yml | 16 ++
.github/workflows/scout.lock.yml | 16 ++
.../workflows/security-compliance.lock.yml | 16 ++
.github/workflows/security-review.lock.yml | 16 ++
.../semantic-function-refactor.lock.yml | 16 ++
.github/workflows/sergo.lock.yml | 16 ++
.../workflows/slide-deck-maintainer.lock.yml | 16 ++
.../workflows/smoke-agent-all-merged.lock.yml | 16 ++
.../workflows/smoke-agent-all-none.lock.yml | 16 ++
.../smoke-agent-public-approved.lock.yml | 16 ++
.../smoke-agent-public-none.lock.yml | 16 ++
.../smoke-agent-scoped-approved.lock.yml | 16 ++
.../workflows/smoke-call-workflow.lock.yml | 16 ++
.github/workflows/smoke-claude.lock.yml | 16 ++
.github/workflows/smoke-codex.lock.yml | 16 ++
.github/workflows/smoke-copilot-arm.lock.yml | 16 ++
.github/workflows/smoke-copilot.lock.yml | 16 ++
.../smoke-create-cross-repo-pr.lock.yml | 16 ++
.github/workflows/smoke-gemini.lock.yml | 16 ++
.github/workflows/smoke-multi-pr.lock.yml | 16 ++
.github/workflows/smoke-project.lock.yml | 16 ++
.../workflows/smoke-service-ports.lock.yml | 16 ++
.github/workflows/smoke-temporary-id.lock.yml | 16 ++
.github/workflows/smoke-test-tools.lock.yml | 16 ++
.../smoke-update-cross-repo-pr.lock.yml | 16 ++
.../smoke-workflow-call-with-inputs.lock.yml | 16 ++
.../workflows/smoke-workflow-call.lock.yml | 16 ++
.../workflows/stale-repo-identifier.lock.yml | 16 ++
.../workflows/static-analysis-report.lock.yml | 16 ++
.../workflows/step-name-alignment.lock.yml | 16 ++
.github/workflows/sub-issue-closer.lock.yml | 16 ++
.github/workflows/super-linter.lock.yml | 16 ++
.../workflows/technical-doc-writer.lock.yml | 16 ++
.github/workflows/terminal-stylist.lock.yml | 16 ++
.../test-create-pr-error-handling.lock.yml | 16 ++
.github/workflows/test-dispatcher.lock.yml | 16 ++
.../test-project-url-default.lock.yml | 16 ++
.github/workflows/tidy.lock.yml | 16 ++
.github/workflows/token-logs-fetch.lock.yml | 16 ++
.github/workflows/typist.lock.yml | 16 ++
.../workflows/ubuntu-image-analyzer.lock.yml | 16 ++
.github/workflows/unbloat-docs.lock.yml | 16 ++
.github/workflows/update-astro.lock.yml | 16 ++
.github/workflows/video-analyzer.lock.yml | 16 ++
.../weekly-blog-post-writer.lock.yml | 16 ++
.../weekly-editors-health-check.lock.yml | 16 ++
.../workflows/weekly-issue-summary.lock.yml | 16 ++
.../weekly-safe-outputs-spec-review.lock.yml | 16 ++
.github/workflows/workflow-generator.lock.yml | 16 ++
.../workflow-health-manager.lock.yml | 16 ++
.../workflows/workflow-normalizer.lock.yml | 16 ++
.../workflow-skill-extractor.lock.yml | 16 ++
.../js/generate_observability_summary.cjs | 9 +
actions/setup/js/send_otlp_span.cjs | 169 +++++++++++++++---
actions/setup/js/send_otlp_span.test.cjs | 158 +++++++++++++++-
pkg/workflow/compiler_safe_outputs_job.go | 3 +
pkg/workflow/notify_comment.go | 3 +
pkg/workflow/observability_otlp.go | 22 ++-
pkg/workflow/observability_otlp_test.go | 19 ++
185 files changed, 3205 insertions(+), 26 deletions(-)
diff --git a/.github/workflows/agent-performance-analyzer.lock.yml b/.github/workflows/agent-performance-analyzer.lock.yml
index c657032a00b..f3cc273fb66 100644
--- a/.github/workflows/agent-performance-analyzer.lock.yml
+++ b/.github/workflows/agent-performance-analyzer.lock.yml
@@ -1017,6 +1017,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1377,4 +1385,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/agent-persona-explorer.lock.yml b/.github/workflows/agent-persona-explorer.lock.yml
index b9c46d1a1b1..4524c7b3239 100644
--- a/.github/workflows/agent-persona-explorer.lock.yml
+++ b/.github/workflows/agent-persona-explorer.lock.yml
@@ -965,6 +965,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1233,6 +1241,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/agentic-observability-kit.lock.yml b/.github/workflows/agentic-observability-kit.lock.yml
index c0b18581084..90fca0a1496 100644
--- a/.github/workflows/agentic-observability-kit.lock.yml
+++ b/.github/workflows/agentic-observability-kit.lock.yml
@@ -966,6 +966,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1208,4 +1216,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/ai-moderator.lock.yml b/.github/workflows/ai-moderator.lock.yml
index e98e1ab042b..19f174d1568 100644
--- a/.github/workflows/ai-moderator.lock.yml
+++ b/.github/workflows/ai-moderator.lock.yml
@@ -932,6 +932,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
pre_activation:
runs-on: ubuntu-slim
@@ -1079,6 +1087,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
unlock:
needs:
diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml
index d51da953a75..2433183d044 100644
--- a/.github/workflows/archie.lock.yml
+++ b/.github/workflows/archie.lock.yml
@@ -986,6 +986,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1272,4 +1280,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml
index 7bf4a704e2c..6fbed2d7433 100644
--- a/.github/workflows/artifacts-summary.lock.yml
+++ b/.github/workflows/artifacts-summary.lock.yml
@@ -846,6 +846,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1084,4 +1092,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml
index 215b62300d0..6a710524a1d 100644
--- a/.github/workflows/audit-workflows.lock.yml
+++ b/.github/workflows/audit-workflows.lock.yml
@@ -1122,6 +1122,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1459,6 +1467,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/auto-triage-issues.lock.yml b/.github/workflows/auto-triage-issues.lock.yml
index 69cd2fe3b02..427ca520781 100644
--- a/.github/workflows/auto-triage-issues.lock.yml
+++ b/.github/workflows/auto-triage-issues.lock.yml
@@ -901,6 +901,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1188,4 +1196,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml
index ae19ddfe702..94dcc39c499 100644
--- a/.github/workflows/blog-auditor.lock.yml
+++ b/.github/workflows/blog-auditor.lock.yml
@@ -981,6 +981,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1233,4 +1241,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/bot-detection.lock.yml b/.github/workflows/bot-detection.lock.yml
index 24613322133..e055a5b4532 100644
--- a/.github/workflows/bot-detection.lock.yml
+++ b/.github/workflows/bot-detection.lock.yml
@@ -925,6 +925,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
precompute:
runs-on: ubuntu-latest
@@ -1815,4 +1823,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml
index ad4e493d55c..47e7ea25c0b 100644
--- a/.github/workflows/brave.lock.yml
+++ b/.github/workflows/brave.lock.yml
@@ -932,6 +932,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1218,4 +1226,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/breaking-change-checker.lock.yml b/.github/workflows/breaking-change-checker.lock.yml
index 20be33672f2..5423b80fca7 100644
--- a/.github/workflows/breaking-change-checker.lock.yml
+++ b/.github/workflows/breaking-change-checker.lock.yml
@@ -883,6 +883,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1186,4 +1194,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml
index 3b9f3c36c24..56c206d7506 100644
--- a/.github/workflows/changeset.lock.yml
+++ b/.github/workflows/changeset.lock.yml
@@ -947,6 +947,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
pre_activation:
if: >
@@ -1097,6 +1105,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/ci-coach.lock.yml b/.github/workflows/ci-coach.lock.yml
index 0b522b09a09..20b34afff6c 100644
--- a/.github/workflows/ci-coach.lock.yml
+++ b/.github/workflows/ci-coach.lock.yml
@@ -945,6 +945,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1216,6 +1224,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml
index f419cafd0a0..eb1c0ed6a9e 100644
--- a/.github/workflows/ci-doctor.lock.yml
+++ b/.github/workflows/ci-doctor.lock.yml
@@ -1105,6 +1105,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1380,6 +1388,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/claude-code-user-docs-review.lock.yml b/.github/workflows/claude-code-user-docs-review.lock.yml
index ca6bb900713..aaa01219d3c 100644
--- a/.github/workflows/claude-code-user-docs-review.lock.yml
+++ b/.github/workflows/claude-code-user-docs-review.lock.yml
@@ -952,6 +952,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1205,6 +1213,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/claude-token-optimizer.lock.yml b/.github/workflows/claude-token-optimizer.lock.yml
index 19003b55602..62b15765f5e 100644
--- a/.github/workflows/claude-token-optimizer.lock.yml
+++ b/.github/workflows/claude-token-optimizer.lock.yml
@@ -888,6 +888,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1172,4 +1180,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/claude-token-usage-analyzer.lock.yml b/.github/workflows/claude-token-usage-analyzer.lock.yml
index d475ff952c1..b01d9d1efcf 100644
--- a/.github/workflows/claude-token-usage-analyzer.lock.yml
+++ b/.github/workflows/claude-token-usage-analyzer.lock.yml
@@ -871,6 +871,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1110,4 +1118,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml
index 26b8ee0ccc2..900433d7f22 100644
--- a/.github/workflows/cli-consistency-checker.lock.yml
+++ b/.github/workflows/cli-consistency-checker.lock.yml
@@ -846,6 +846,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1085,4 +1093,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml
index b1ae0f0a1ca..808c741ffab 100644
--- a/.github/workflows/cli-version-checker.lock.yml
+++ b/.github/workflows/cli-version-checker.lock.yml
@@ -955,6 +955,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1207,6 +1215,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml
index 2cb5eb38776..4c849b7b82d 100644
--- a/.github/workflows/cloclo.lock.yml
+++ b/.github/workflows/cloclo.lock.yml
@@ -1316,6 +1316,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1647,6 +1655,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/code-scanning-fixer.lock.yml b/.github/workflows/code-scanning-fixer.lock.yml
index 4bed62d0c7e..d4bf8895e60 100644
--- a/.github/workflows/code-scanning-fixer.lock.yml
+++ b/.github/workflows/code-scanning-fixer.lock.yml
@@ -940,6 +940,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1340,6 +1348,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/code-simplifier.lock.yml b/.github/workflows/code-simplifier.lock.yml
index 89083e05b14..2eb7f331904 100644
--- a/.github/workflows/code-simplifier.lock.yml
+++ b/.github/workflows/code-simplifier.lock.yml
@@ -875,6 +875,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1189,6 +1197,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml
index e9fe2d85fdb..aa8c84bac2d 100644
--- a/.github/workflows/commit-changes-analyzer.lock.yml
+++ b/.github/workflows/commit-changes-analyzer.lock.yml
@@ -911,6 +911,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1162,4 +1170,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/constraint-solving-potd.lock.yml b/.github/workflows/constraint-solving-potd.lock.yml
index 7b653c74978..a5d520b43b4 100644
--- a/.github/workflows/constraint-solving-potd.lock.yml
+++ b/.github/workflows/constraint-solving-potd.lock.yml
@@ -862,6 +862,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1098,6 +1106,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/contribution-check.lock.yml b/.github/workflows/contribution-check.lock.yml
index 25700435c94..833b0a29813 100644
--- a/.github/workflows/contribution-check.lock.yml
+++ b/.github/workflows/contribution-check.lock.yml
@@ -897,6 +897,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1138,4 +1146,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml
index 3137a1d86ed..efad9475ab4 100644
--- a/.github/workflows/copilot-agent-analysis.lock.yml
+++ b/.github/workflows/copilot-agent-analysis.lock.yml
@@ -1002,6 +1002,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1338,6 +1346,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/copilot-cli-deep-research.lock.yml b/.github/workflows/copilot-cli-deep-research.lock.yml
index dc3fc7a79b7..d9369c1c647 100644
--- a/.github/workflows/copilot-cli-deep-research.lock.yml
+++ b/.github/workflows/copilot-cli-deep-research.lock.yml
@@ -909,6 +909,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1232,4 +1240,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/copilot-pr-merged-report.lock.yml b/.github/workflows/copilot-pr-merged-report.lock.yml
index ee0ed960fc8..41404df4802 100644
--- a/.github/workflows/copilot-pr-merged-report.lock.yml
+++ b/.github/workflows/copilot-pr-merged-report.lock.yml
@@ -1032,6 +1032,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1270,6 +1278,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml
index 8b1594e11fe..899bf51b21d 100644
--- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml
+++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml
@@ -1003,6 +1003,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1326,6 +1334,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml
index 68c68005e6c..5ea6416f99b 100644
--- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml
+++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml
@@ -938,6 +938,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1261,6 +1269,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml
index 4eb630f78e1..651178ed553 100644
--- a/.github/workflows/copilot-session-insights.lock.yml
+++ b/.github/workflows/copilot-session-insights.lock.yml
@@ -1065,6 +1065,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1401,6 +1409,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/copilot-token-optimizer.lock.yml b/.github/workflows/copilot-token-optimizer.lock.yml
index 9270436f58d..726a553ad92 100644
--- a/.github/workflows/copilot-token-optimizer.lock.yml
+++ b/.github/workflows/copilot-token-optimizer.lock.yml
@@ -888,6 +888,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1172,4 +1180,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/copilot-token-usage-analyzer.lock.yml b/.github/workflows/copilot-token-usage-analyzer.lock.yml
index ee4a6f962b5..24b56069802 100644
--- a/.github/workflows/copilot-token-usage-analyzer.lock.yml
+++ b/.github/workflows/copilot-token-usage-analyzer.lock.yml
@@ -965,6 +965,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1204,6 +1212,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml
index 2b76b67fad1..a51881ddfb7 100644
--- a/.github/workflows/craft.lock.yml
+++ b/.github/workflows/craft.lock.yml
@@ -938,6 +938,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1256,6 +1264,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/daily-architecture-diagram.lock.yml b/.github/workflows/daily-architecture-diagram.lock.yml
index 9209b95832c..c9e4a6ae662 100644
--- a/.github/workflows/daily-architecture-diagram.lock.yml
+++ b/.github/workflows/daily-architecture-diagram.lock.yml
@@ -925,6 +925,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1197,6 +1205,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/daily-assign-issue-to-user.lock.yml b/.github/workflows/daily-assign-issue-to-user.lock.yml
index c6b127436df..62d058bd92b 100644
--- a/.github/workflows/daily-assign-issue-to-user.lock.yml
+++ b/.github/workflows/daily-assign-issue-to-user.lock.yml
@@ -851,6 +851,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1093,4 +1101,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-choice-test.lock.yml b/.github/workflows/daily-choice-test.lock.yml
index 9657b6c3f5a..ed78f7cfab0 100644
--- a/.github/workflows/daily-choice-test.lock.yml
+++ b/.github/workflows/daily-choice-test.lock.yml
@@ -904,6 +904,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1149,6 +1157,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
test_environment:
name: Test Environment Deployment
diff --git a/.github/workflows/daily-cli-performance.lock.yml b/.github/workflows/daily-cli-performance.lock.yml
index ac74bd834ed..9d75d004532 100644
--- a/.github/workflows/daily-cli-performance.lock.yml
+++ b/.github/workflows/daily-cli-performance.lock.yml
@@ -1098,6 +1098,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1481,4 +1489,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-cli-tools-tester.lock.yml b/.github/workflows/daily-cli-tools-tester.lock.yml
index c1b1f7a9f4c..eb573dbf92a 100644
--- a/.github/workflows/daily-cli-tools-tester.lock.yml
+++ b/.github/workflows/daily-cli-tools-tester.lock.yml
@@ -932,6 +932,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1169,4 +1177,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml
index 19d4f55fb15..008958eb20a 100644
--- a/.github/workflows/daily-code-metrics.lock.yml
+++ b/.github/workflows/daily-code-metrics.lock.yml
@@ -1044,6 +1044,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1381,6 +1389,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-community-attribution.lock.yml b/.github/workflows/daily-community-attribution.lock.yml
index 1c404160b1e..2f625f95462 100644
--- a/.github/workflows/daily-community-attribution.lock.yml
+++ b/.github/workflows/daily-community-attribution.lock.yml
@@ -942,6 +942,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1295,6 +1303,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/daily-compiler-quality.lock.yml b/.github/workflows/daily-compiler-quality.lock.yml
index 2fea563fb80..bb539e064b3 100644
--- a/.github/workflows/daily-compiler-quality.lock.yml
+++ b/.github/workflows/daily-compiler-quality.lock.yml
@@ -978,6 +978,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1217,6 +1225,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-copilot-token-report.lock.yml b/.github/workflows/daily-copilot-token-report.lock.yml
index 028fcafa8c2..652033ecabe 100644
--- a/.github/workflows/daily-copilot-token-report.lock.yml
+++ b/.github/workflows/daily-copilot-token-report.lock.yml
@@ -1025,6 +1025,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1349,6 +1357,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-doc-healer.lock.yml b/.github/workflows/daily-doc-healer.lock.yml
index 5d24f397d2e..65d78f8cfde 100644
--- a/.github/workflows/daily-doc-healer.lock.yml
+++ b/.github/workflows/daily-doc-healer.lock.yml
@@ -1098,6 +1098,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1470,6 +1478,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml
index f612d5c3783..db00540ac58 100644
--- a/.github/workflows/daily-doc-updater.lock.yml
+++ b/.github/workflows/daily-doc-updater.lock.yml
@@ -1064,6 +1064,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1429,6 +1437,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/daily-fact.lock.yml b/.github/workflows/daily-fact.lock.yml
index 37c6734bade..2205e84c9d0 100644
--- a/.github/workflows/daily-fact.lock.yml
+++ b/.github/workflows/daily-fact.lock.yml
@@ -927,6 +927,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1166,4 +1174,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml
index f423f33a98a..6b48fa0cce7 100644
--- a/.github/workflows/daily-file-diet.lock.yml
+++ b/.github/workflows/daily-file-diet.lock.yml
@@ -952,6 +952,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1237,4 +1245,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml
index eee10df5905..54694a9b3e6 100644
--- a/.github/workflows/daily-firewall-report.lock.yml
+++ b/.github/workflows/daily-firewall-report.lock.yml
@@ -1021,6 +1021,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1258,6 +1266,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-function-namer.lock.yml b/.github/workflows/daily-function-namer.lock.yml
index 6be76bf1ac8..a3869bf440d 100644
--- a/.github/workflows/daily-function-namer.lock.yml
+++ b/.github/workflows/daily-function-namer.lock.yml
@@ -1013,6 +1013,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1266,6 +1274,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-integrity-analysis.lock.yml b/.github/workflows/daily-integrity-analysis.lock.yml
index a0877808bbc..58f110489d9 100644
--- a/.github/workflows/daily-integrity-analysis.lock.yml
+++ b/.github/workflows/daily-integrity-analysis.lock.yml
@@ -1038,6 +1038,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1275,6 +1283,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-issues-report.lock.yml b/.github/workflows/daily-issues-report.lock.yml
index abd6a1e2e21..205631b1774 100644
--- a/.github/workflows/daily-issues-report.lock.yml
+++ b/.github/workflows/daily-issues-report.lock.yml
@@ -1006,6 +1006,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1273,6 +1281,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-malicious-code-scan.lock.yml b/.github/workflows/daily-malicious-code-scan.lock.yml
index 5c244794b3c..86d03af7a01 100644
--- a/.github/workflows/daily-malicious-code-scan.lock.yml
+++ b/.github/workflows/daily-malicious-code-scan.lock.yml
@@ -856,6 +856,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
safe_outputs:
needs: agent
@@ -947,6 +955,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
upload_code_scanning_sarif:
needs: safe_outputs
diff --git a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml
index e41239b200c..6e908d8a9c7 100644
--- a/.github/workflows/daily-mcp-concurrency-analysis.lock.yml
+++ b/.github/workflows/daily-mcp-concurrency-analysis.lock.yml
@@ -991,6 +991,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1245,6 +1253,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml
index 2e4043d87c4..b4058fb33cb 100644
--- a/.github/workflows/daily-multi-device-docs-tester.lock.yml
+++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml
@@ -1029,6 +1029,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1282,6 +1290,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
upload_assets:
needs: agent
diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml
index b2875b1b455..7e68f4d8dc5 100644
--- a/.github/workflows/daily-news.lock.yml
+++ b/.github/workflows/daily-news.lock.yml
@@ -1079,6 +1079,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1403,6 +1411,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-observability-report.lock.yml b/.github/workflows/daily-observability-report.lock.yml
index 8b15f2b7cfe..4794cf89c83 100644
--- a/.github/workflows/daily-observability-report.lock.yml
+++ b/.github/workflows/daily-observability-report.lock.yml
@@ -961,6 +961,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1228,4 +1236,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-performance-summary.lock.yml b/.github/workflows/daily-performance-summary.lock.yml
index 277e605dcb1..183bbae6982 100644
--- a/.github/workflows/daily-performance-summary.lock.yml
+++ b/.github/workflows/daily-performance-summary.lock.yml
@@ -1433,6 +1433,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1670,6 +1678,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-regulatory.lock.yml b/.github/workflows/daily-regulatory.lock.yml
index 8cc3f64fda0..9d560ec1d2d 100644
--- a/.github/workflows/daily-regulatory.lock.yml
+++ b/.github/workflows/daily-regulatory.lock.yml
@@ -1344,6 +1344,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1581,4 +1589,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-rendering-scripts-verifier.lock.yml b/.github/workflows/daily-rendering-scripts-verifier.lock.yml
index d3013b9ea7f..e2043736d0a 100644
--- a/.github/workflows/daily-rendering-scripts-verifier.lock.yml
+++ b/.github/workflows/daily-rendering-scripts-verifier.lock.yml
@@ -1073,6 +1073,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1402,6 +1410,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml
index 0f92d00f5ee..74fe23ed907 100644
--- a/.github/workflows/daily-repo-chronicle.lock.yml
+++ b/.github/workflows/daily-repo-chronicle.lock.yml
@@ -942,6 +942,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1181,6 +1189,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-safe-output-integrator.lock.yml b/.github/workflows/daily-safe-output-integrator.lock.yml
index 6b5a2708c41..d3bd01a5959 100644
--- a/.github/workflows/daily-safe-output-integrator.lock.yml
+++ b/.github/workflows/daily-safe-output-integrator.lock.yml
@@ -896,6 +896,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1167,6 +1175,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/daily-safe-output-optimizer.lock.yml b/.github/workflows/daily-safe-output-optimizer.lock.yml
index b7fc7c31239..ea3d6aa269b 100644
--- a/.github/workflows/daily-safe-output-optimizer.lock.yml
+++ b/.github/workflows/daily-safe-output-optimizer.lock.yml
@@ -1056,6 +1056,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1353,6 +1361,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/daily-safe-outputs-conformance.lock.yml b/.github/workflows/daily-safe-outputs-conformance.lock.yml
index 8dd61390ddb..22937458f91 100644
--- a/.github/workflows/daily-safe-outputs-conformance.lock.yml
+++ b/.github/workflows/daily-safe-outputs-conformance.lock.yml
@@ -913,6 +913,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1166,4 +1174,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-secrets-analysis.lock.yml b/.github/workflows/daily-secrets-analysis.lock.yml
index 90255fe9213..f6f463202bd 100644
--- a/.github/workflows/daily-secrets-analysis.lock.yml
+++ b/.github/workflows/daily-secrets-analysis.lock.yml
@@ -851,6 +851,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1090,4 +1098,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-security-red-team.lock.yml b/.github/workflows/daily-security-red-team.lock.yml
index 80c06d69fc1..5005ec24e9e 100644
--- a/.github/workflows/daily-security-red-team.lock.yml
+++ b/.github/workflows/daily-security-red-team.lock.yml
@@ -917,6 +917,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1170,4 +1178,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-semgrep-scan.lock.yml b/.github/workflows/daily-semgrep-scan.lock.yml
index 1dc79480d95..c708a76d868 100644
--- a/.github/workflows/daily-semgrep-scan.lock.yml
+++ b/.github/workflows/daily-semgrep-scan.lock.yml
@@ -882,6 +882,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1126,6 +1134,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
upload_code_scanning_sarif:
needs: safe_outputs
diff --git a/.github/workflows/daily-syntax-error-quality.lock.yml b/.github/workflows/daily-syntax-error-quality.lock.yml
index 32894970252..271bd0309cb 100644
--- a/.github/workflows/daily-syntax-error-quality.lock.yml
+++ b/.github/workflows/daily-syntax-error-quality.lock.yml
@@ -885,6 +885,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1125,4 +1133,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-team-evolution-insights.lock.yml b/.github/workflows/daily-team-evolution-insights.lock.yml
index 9f01159d53b..e2a36b355db 100644
--- a/.github/workflows/daily-team-evolution-insights.lock.yml
+++ b/.github/workflows/daily-team-evolution-insights.lock.yml
@@ -913,6 +913,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1165,4 +1173,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml
index 15d6004be07..f495258896f 100644
--- a/.github/workflows/daily-team-status.lock.yml
+++ b/.github/workflows/daily-team-status.lock.yml
@@ -874,6 +874,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1146,4 +1154,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-testify-uber-super-expert.lock.yml b/.github/workflows/daily-testify-uber-super-expert.lock.yml
index ea2e4bc3d28..06955e61eb3 100644
--- a/.github/workflows/daily-testify-uber-super-expert.lock.yml
+++ b/.github/workflows/daily-testify-uber-super-expert.lock.yml
@@ -994,6 +994,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1364,4 +1372,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/daily-workflow-updater.lock.yml b/.github/workflows/daily-workflow-updater.lock.yml
index 768fd06263c..d313d8c7c99 100644
--- a/.github/workflows/daily-workflow-updater.lock.yml
+++ b/.github/workflows/daily-workflow-updater.lock.yml
@@ -855,6 +855,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1126,6 +1134,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/dead-code-remover.lock.yml b/.github/workflows/dead-code-remover.lock.yml
index f2e95529c16..e0952431c36 100644
--- a/.github/workflows/dead-code-remover.lock.yml
+++ b/.github/workflows/dead-code-remover.lock.yml
@@ -912,6 +912,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1227,6 +1235,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/deep-report.lock.yml b/.github/workflows/deep-report.lock.yml
index a39a364d3f1..2ab2b5307c7 100644
--- a/.github/workflows/deep-report.lock.yml
+++ b/.github/workflows/deep-report.lock.yml
@@ -1150,6 +1150,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1489,6 +1497,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/delight.lock.yml b/.github/workflows/delight.lock.yml
index fd82f72be38..36c50c93ed9 100644
--- a/.github/workflows/delight.lock.yml
+++ b/.github/workflows/delight.lock.yml
@@ -953,6 +953,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1280,4 +1288,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/dependabot-burner.lock.yml b/.github/workflows/dependabot-burner.lock.yml
index 486ea8e62c6..95cef2d0a9a 100644
--- a/.github/workflows/dependabot-burner.lock.yml
+++ b/.github/workflows/dependabot-burner.lock.yml
@@ -857,6 +857,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1126,4 +1134,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml
index 6ebfcdf4602..e1032d1599b 100644
--- a/.github/workflows/dependabot-go-checker.lock.yml
+++ b/.github/workflows/dependabot-go-checker.lock.yml
@@ -875,6 +875,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1112,4 +1120,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml
index e58f0c79141..d9edd66d9af 100644
--- a/.github/workflows/dev-hawk.lock.yml
+++ b/.github/workflows/dev-hawk.lock.yml
@@ -953,6 +953,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1228,4 +1236,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml
index efa17384dca..cffa45f451e 100644
--- a/.github/workflows/dev.lock.yml
+++ b/.github/workflows/dev.lock.yml
@@ -999,6 +999,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1344,4 +1352,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml
index 91771e6d276..9a1d4a47893 100644
--- a/.github/workflows/developer-docs-consolidator.lock.yml
+++ b/.github/workflows/developer-docs-consolidator.lock.yml
@@ -1188,6 +1188,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1626,6 +1634,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml
index 1ac6e6191bd..423ac27615b 100644
--- a/.github/workflows/dictation-prompt.lock.yml
+++ b/.github/workflows/dictation-prompt.lock.yml
@@ -933,6 +933,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1272,6 +1280,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/discussion-task-miner.lock.yml b/.github/workflows/discussion-task-miner.lock.yml
index f7d8f662e41..8ae19fb7aad 100644
--- a/.github/workflows/discussion-task-miner.lock.yml
+++ b/.github/workflows/discussion-task-miner.lock.yml
@@ -942,6 +942,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1272,4 +1280,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml
index d48b31170a4..e60541c521f 100644
--- a/.github/workflows/docs-noob-tester.lock.yml
+++ b/.github/workflows/docs-noob-tester.lock.yml
@@ -901,6 +901,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1139,6 +1147,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
upload_assets:
needs: agent
diff --git a/.github/workflows/draft-pr-cleanup.lock.yml b/.github/workflows/draft-pr-cleanup.lock.yml
index 1dd513b7c3f..27e21905fd1 100644
--- a/.github/workflows/draft-pr-cleanup.lock.yml
+++ b/.github/workflows/draft-pr-cleanup.lock.yml
@@ -887,6 +887,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1129,4 +1137,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml
index b3ea43caaa5..137ab98cc06 100644
--- a/.github/workflows/duplicate-code-detector.lock.yml
+++ b/.github/workflows/duplicate-code-detector.lock.yml
@@ -955,6 +955,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1207,4 +1215,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml
index 4700d9c2fb2..4a90e84b122 100644
--- a/.github/workflows/example-workflow-analyzer.lock.yml
+++ b/.github/workflows/example-workflow-analyzer.lock.yml
@@ -981,6 +981,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1232,4 +1240,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/firewall-escape.lock.yml b/.github/workflows/firewall-escape.lock.yml
index 71872c4dea0..dc93f07cf38 100644
--- a/.github/workflows/firewall-escape.lock.yml
+++ b/.github/workflows/firewall-escape.lock.yml
@@ -940,6 +940,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1336,6 +1344,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/functional-pragmatist.lock.yml b/.github/workflows/functional-pragmatist.lock.yml
index 8027b9e7159..40047985772 100644
--- a/.github/workflows/functional-pragmatist.lock.yml
+++ b/.github/workflows/functional-pragmatist.lock.yml
@@ -867,6 +867,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1136,6 +1144,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/github-mcp-structural-analysis.lock.yml b/.github/workflows/github-mcp-structural-analysis.lock.yml
index b4eda268243..0c382aceda5 100644
--- a/.github/workflows/github-mcp-structural-analysis.lock.yml
+++ b/.github/workflows/github-mcp-structural-analysis.lock.yml
@@ -1006,6 +1006,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1257,6 +1265,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml
index 4034e930183..4c5db2d682a 100644
--- a/.github/workflows/github-mcp-tools-report.lock.yml
+++ b/.github/workflows/github-mcp-tools-report.lock.yml
@@ -991,6 +991,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1275,6 +1283,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/github-remote-mcp-auth-test.lock.yml b/.github/workflows/github-remote-mcp-auth-test.lock.yml
index a3fd4d409a7..1d5f98630f0 100644
--- a/.github/workflows/github-remote-mcp-auth-test.lock.yml
+++ b/.github/workflows/github-remote-mcp-auth-test.lock.yml
@@ -864,6 +864,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1100,4 +1108,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml
index f804a295f3a..fd13a1a8dfb 100644
--- a/.github/workflows/glossary-maintainer.lock.yml
+++ b/.github/workflows/glossary-maintainer.lock.yml
@@ -1087,6 +1087,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1509,6 +1517,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/go-fan.lock.yml b/.github/workflows/go-fan.lock.yml
index 5bc52d7f61e..d171c4f1406 100644
--- a/.github/workflows/go-fan.lock.yml
+++ b/.github/workflows/go-fan.lock.yml
@@ -1039,6 +1039,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1291,6 +1299,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml
index 54d59f84e66..cca7dc6e74a 100644
--- a/.github/workflows/go-logger.lock.yml
+++ b/.github/workflows/go-logger.lock.yml
@@ -1151,6 +1151,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1434,6 +1442,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml
index 33f1c565b9d..f3bfb276456 100644
--- a/.github/workflows/go-pattern-detector.lock.yml
+++ b/.github/workflows/go-pattern-detector.lock.yml
@@ -979,6 +979,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1231,4 +1239,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/gpclean.lock.yml b/.github/workflows/gpclean.lock.yml
index a01bed112b2..eac816803a5 100644
--- a/.github/workflows/gpclean.lock.yml
+++ b/.github/workflows/gpclean.lock.yml
@@ -895,6 +895,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1132,6 +1140,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml
index 9fbe804182a..0524d864ce3 100644
--- a/.github/workflows/grumpy-reviewer.lock.yml
+++ b/.github/workflows/grumpy-reviewer.lock.yml
@@ -1009,6 +1009,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1287,6 +1295,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/hourly-ci-cleaner.lock.yml b/.github/workflows/hourly-ci-cleaner.lock.yml
index 0c7e82b6234..53fabe66159 100644
--- a/.github/workflows/hourly-ci-cleaner.lock.yml
+++ b/.github/workflows/hourly-ci-cleaner.lock.yml
@@ -975,6 +975,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1244,6 +1252,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml
index 8ad2199d0aa..e7d1db192e6 100644
--- a/.github/workflows/instructions-janitor.lock.yml
+++ b/.github/workflows/instructions-janitor.lock.yml
@@ -973,6 +973,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1256,6 +1264,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/issue-arborist.lock.yml b/.github/workflows/issue-arborist.lock.yml
index 511ee8af186..9fb3a056abc 100644
--- a/.github/workflows/issue-arborist.lock.yml
+++ b/.github/workflows/issue-arborist.lock.yml
@@ -946,6 +946,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1182,4 +1190,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/issue-monster.lock.yml b/.github/workflows/issue-monster.lock.yml
index 44a7226bb55..604e36bc5ed 100644
--- a/.github/workflows/issue-monster.lock.yml
+++ b/.github/workflows/issue-monster.lock.yml
@@ -1250,6 +1250,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1934,4 +1942,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/issue-triage-agent.lock.yml b/.github/workflows/issue-triage-agent.lock.yml
index 50273d973c0..8585fc2b1c3 100644
--- a/.github/workflows/issue-triage-agent.lock.yml
+++ b/.github/workflows/issue-triage-agent.lock.yml
@@ -847,6 +847,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1086,4 +1094,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/jsweep.lock.yml b/.github/workflows/jsweep.lock.yml
index 6891dae0316..ec43317ded0 100644
--- a/.github/workflows/jsweep.lock.yml
+++ b/.github/workflows/jsweep.lock.yml
@@ -972,6 +972,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1241,6 +1249,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/layout-spec-maintainer.lock.yml b/.github/workflows/layout-spec-maintainer.lock.yml
index bb55275d1f7..90fb1b7b365 100644
--- a/.github/workflows/layout-spec-maintainer.lock.yml
+++ b/.github/workflows/layout-spec-maintainer.lock.yml
@@ -899,6 +899,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1168,6 +1176,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml
index 666310ba467..646981d4f27 100644
--- a/.github/workflows/lockfile-stats.lock.yml
+++ b/.github/workflows/lockfile-stats.lock.yml
@@ -945,6 +945,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1196,6 +1204,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml
index 157b6adc5cd..4b736cd7461 100644
--- a/.github/workflows/mcp-inspector.lock.yml
+++ b/.github/workflows/mcp-inspector.lock.yml
@@ -1400,6 +1400,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1913,6 +1921,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml
index 6dea2d5a8b1..dab53dd03a6 100644
--- a/.github/workflows/mergefest.lock.yml
+++ b/.github/workflows/mergefest.lock.yml
@@ -952,6 +952,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1263,6 +1271,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml
index 5b00ac160df..42c57671499 100644
--- a/.github/workflows/notion-issue-summary.lock.yml
+++ b/.github/workflows/notion-issue-summary.lock.yml
@@ -861,6 +861,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1226,4 +1234,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/org-health-report.lock.yml b/.github/workflows/org-health-report.lock.yml
index 024c516cb36..5171916fa41 100644
--- a/.github/workflows/org-health-report.lock.yml
+++ b/.github/workflows/org-health-report.lock.yml
@@ -950,6 +950,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1186,6 +1194,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml
index 1b12f733f9c..76c33079ce6 100644
--- a/.github/workflows/pdf-summary.lock.yml
+++ b/.github/workflows/pdf-summary.lock.yml
@@ -1026,6 +1026,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1310,6 +1318,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml
index a6a8372f560..4a8899b009b 100644
--- a/.github/workflows/plan.lock.yml
+++ b/.github/workflows/plan.lock.yml
@@ -955,6 +955,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1237,4 +1245,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml
index 8da1309cb78..0344a2c8fba 100644
--- a/.github/workflows/poem-bot.lock.yml
+++ b/.github/workflows/poem-bot.lock.yml
@@ -1315,6 +1315,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1611,6 +1619,14 @@ jobs:
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/create_agent_session.cjs'); await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/portfolio-analyst.lock.yml b/.github/workflows/portfolio-analyst.lock.yml
index b0b6e2e5154..99d1f49ab09 100644
--- a/.github/workflows/portfolio-analyst.lock.yml
+++ b/.github/workflows/portfolio-analyst.lock.yml
@@ -1040,6 +1040,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1277,6 +1285,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml
index 51505f76ed9..f7ada2229ca 100644
--- a/.github/workflows/pr-nitpick-reviewer.lock.yml
+++ b/.github/workflows/pr-nitpick-reviewer.lock.yml
@@ -1023,6 +1023,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1305,6 +1313,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/pr-triage-agent.lock.yml b/.github/workflows/pr-triage-agent.lock.yml
index 3a479d23c34..45885d2316d 100644
--- a/.github/workflows/pr-triage-agent.lock.yml
+++ b/.github/workflows/pr-triage-agent.lock.yml
@@ -937,6 +937,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1264,4 +1272,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml
index d3c53e99384..ce4796f9484 100644
--- a/.github/workflows/prompt-clustering-analysis.lock.yml
+++ b/.github/workflows/prompt-clustering-analysis.lock.yml
@@ -1084,6 +1084,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1335,6 +1343,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml
index af480ec4935..a6c1b7feed9 100644
--- a/.github/workflows/python-data-charts.lock.yml
+++ b/.github/workflows/python-data-charts.lock.yml
@@ -1016,6 +1016,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1252,6 +1260,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml
index da890e2f634..aa775f7844a 100644
--- a/.github/workflows/q.lock.yml
+++ b/.github/workflows/q.lock.yml
@@ -1183,6 +1183,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1499,6 +1507,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/refiner.lock.yml b/.github/workflows/refiner.lock.yml
index fad74c6f31c..c6cef4b5f51 100644
--- a/.github/workflows/refiner.lock.yml
+++ b/.github/workflows/refiner.lock.yml
@@ -916,6 +916,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1223,6 +1231,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml
index 50f6cc183f7..d3c62939766 100644
--- a/.github/workflows/release.lock.yml
+++ b/.github/workflows/release.lock.yml
@@ -896,6 +896,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
config:
needs:
@@ -1504,6 +1512,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
sync_actions:
needs:
diff --git a/.github/workflows/repo-audit-analyzer.lock.yml b/.github/workflows/repo-audit-analyzer.lock.yml
index dbfc6d34049..94c108017f7 100644
--- a/.github/workflows/repo-audit-analyzer.lock.yml
+++ b/.github/workflows/repo-audit-analyzer.lock.yml
@@ -893,6 +893,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1129,6 +1137,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml
index ab403ba1775..2b14829e966 100644
--- a/.github/workflows/repo-tree-map.lock.yml
+++ b/.github/workflows/repo-tree-map.lock.yml
@@ -850,6 +850,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1086,4 +1094,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml
index c99a7a0d941..3ad0c2c1c4c 100644
--- a/.github/workflows/repository-quality-improver.lock.yml
+++ b/.github/workflows/repository-quality-improver.lock.yml
@@ -952,6 +952,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1188,6 +1196,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml
index d16f3beaad2..d705993f5eb 100644
--- a/.github/workflows/research.lock.yml
+++ b/.github/workflows/research.lock.yml
@@ -880,6 +880,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1116,4 +1124,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml
index b892da87435..c56fd4b4c1e 100644
--- a/.github/workflows/safe-output-health.lock.yml
+++ b/.github/workflows/safe-output-health.lock.yml
@@ -1046,6 +1046,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1297,6 +1305,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml
index 0af51d57c99..e0a79448ea5 100644
--- a/.github/workflows/schema-consistency-checker.lock.yml
+++ b/.github/workflows/schema-consistency-checker.lock.yml
@@ -945,6 +945,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1196,6 +1204,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/schema-feature-coverage.lock.yml b/.github/workflows/schema-feature-coverage.lock.yml
index 29deadc8ec9..7d03826fbb9 100644
--- a/.github/workflows/schema-feature-coverage.lock.yml
+++ b/.github/workflows/schema-feature-coverage.lock.yml
@@ -880,6 +880,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1146,6 +1154,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml
index 6d83685df5b..c65a320e687 100644
--- a/.github/workflows/scout.lock.yml
+++ b/.github/workflows/scout.lock.yml
@@ -1201,6 +1201,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1500,6 +1508,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/security-compliance.lock.yml b/.github/workflows/security-compliance.lock.yml
index 86011bf3339..0e811d98a6d 100644
--- a/.github/workflows/security-compliance.lock.yml
+++ b/.github/workflows/security-compliance.lock.yml
@@ -905,6 +905,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1227,4 +1235,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/security-review.lock.yml b/.github/workflows/security-review.lock.yml
index 6fbd6a7b355..8dd6a1ad2c7 100644
--- a/.github/workflows/security-review.lock.yml
+++ b/.github/workflows/security-review.lock.yml
@@ -1067,6 +1067,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1347,6 +1355,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml
index 925ebf78d03..19fc1dbcfaa 100644
--- a/.github/workflows/semantic-function-refactor.lock.yml
+++ b/.github/workflows/semantic-function-refactor.lock.yml
@@ -1011,6 +1011,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1263,4 +1271,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/sergo.lock.yml b/.github/workflows/sergo.lock.yml
index 0f3473bdcfd..2ce7567339f 100644
--- a/.github/workflows/sergo.lock.yml
+++ b/.github/workflows/sergo.lock.yml
@@ -1028,6 +1028,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1280,6 +1288,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/slide-deck-maintainer.lock.yml b/.github/workflows/slide-deck-maintainer.lock.yml
index 894bbff99b2..78397b7e9fd 100644
--- a/.github/workflows/slide-deck-maintainer.lock.yml
+++ b/.github/workflows/slide-deck-maintainer.lock.yml
@@ -987,6 +987,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1301,6 +1309,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/smoke-agent-all-merged.lock.yml b/.github/workflows/smoke-agent-all-merged.lock.yml
index e7e8622c41d..8057899abe7 100644
--- a/.github/workflows/smoke-agent-all-merged.lock.yml
+++ b/.github/workflows/smoke-agent-all-merged.lock.yml
@@ -908,6 +908,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1181,4 +1189,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/smoke-agent-all-none.lock.yml b/.github/workflows/smoke-agent-all-none.lock.yml
index 01a8a1fcc42..e2285a97ba7 100644
--- a/.github/workflows/smoke-agent-all-none.lock.yml
+++ b/.github/workflows/smoke-agent-all-none.lock.yml
@@ -908,6 +908,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1181,4 +1189,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/smoke-agent-public-approved.lock.yml b/.github/workflows/smoke-agent-public-approved.lock.yml
index 26d9b3356a4..41ad4698e28 100644
--- a/.github/workflows/smoke-agent-public-approved.lock.yml
+++ b/.github/workflows/smoke-agent-public-approved.lock.yml
@@ -943,6 +943,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1237,4 +1245,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/smoke-agent-public-none.lock.yml b/.github/workflows/smoke-agent-public-none.lock.yml
index 3d8c74d83ac..05d5b44192d 100644
--- a/.github/workflows/smoke-agent-public-none.lock.yml
+++ b/.github/workflows/smoke-agent-public-none.lock.yml
@@ -908,6 +908,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1181,4 +1189,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/smoke-agent-scoped-approved.lock.yml b/.github/workflows/smoke-agent-scoped-approved.lock.yml
index aee63820592..d543b431ab9 100644
--- a/.github/workflows/smoke-agent-scoped-approved.lock.yml
+++ b/.github/workflows/smoke-agent-scoped-approved.lock.yml
@@ -918,6 +918,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1191,4 +1199,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/smoke-call-workflow.lock.yml b/.github/workflows/smoke-call-workflow.lock.yml
index b53c0a5358d..d9996706389 100644
--- a/.github/workflows/smoke-call-workflow.lock.yml
+++ b/.github/workflows/smoke-call-workflow.lock.yml
@@ -881,6 +881,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1149,4 +1157,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml
index 5b6bc94ea0e..b306f4f5087 100644
--- a/.github/workflows/smoke-claude.lock.yml
+++ b/.github/workflows/smoke-claude.lock.yml
@@ -2513,6 +2513,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -2842,6 +2850,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml
index b7cf767e10c..12fa310e207 100644
--- a/.github/workflows/smoke-codex.lock.yml
+++ b/.github/workflows/smoke-codex.lock.yml
@@ -1473,6 +1473,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1829,6 +1837,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/smoke-copilot-arm.lock.yml b/.github/workflows/smoke-copilot-arm.lock.yml
index 3cdb9535413..e91eddbc1bc 100644
--- a/.github/workflows/smoke-copilot-arm.lock.yml
+++ b/.github/workflows/smoke-copilot-arm.lock.yml
@@ -1849,6 +1849,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -2128,6 +2136,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
send_slack_message:
needs:
diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml
index daffe564d9c..7a0e924a4fa 100644
--- a/.github/workflows/smoke-copilot.lock.yml
+++ b/.github/workflows/smoke-copilot.lock.yml
@@ -1901,6 +1901,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -2178,6 +2186,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
send_slack_message:
needs:
diff --git a/.github/workflows/smoke-create-cross-repo-pr.lock.yml b/.github/workflows/smoke-create-cross-repo-pr.lock.yml
index 6e6991ed9cd..b976587743f 100644
--- a/.github/workflows/smoke-create-cross-repo-pr.lock.yml
+++ b/.github/workflows/smoke-create-cross-repo-pr.lock.yml
@@ -989,6 +989,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1303,6 +1311,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/smoke-gemini.lock.yml b/.github/workflows/smoke-gemini.lock.yml
index c99b8fe1c26..0e6dc239842 100644
--- a/.github/workflows/smoke-gemini.lock.yml
+++ b/.github/workflows/smoke-gemini.lock.yml
@@ -1135,6 +1135,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1422,6 +1430,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/smoke-multi-pr.lock.yml b/.github/workflows/smoke-multi-pr.lock.yml
index a98f29959d3..979324ebdc3 100644
--- a/.github/workflows/smoke-multi-pr.lock.yml
+++ b/.github/workflows/smoke-multi-pr.lock.yml
@@ -974,6 +974,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1281,6 +1289,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/smoke-project.lock.yml b/.github/workflows/smoke-project.lock.yml
index f985fd7567a..0761f030259 100644
--- a/.github/workflows/smoke-project.lock.yml
+++ b/.github/workflows/smoke-project.lock.yml
@@ -1107,6 +1107,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1419,6 +1427,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/smoke-service-ports.lock.yml b/.github/workflows/smoke-service-ports.lock.yml
index 68f88b02a60..c13b8101fcd 100644
--- a/.github/workflows/smoke-service-ports.lock.yml
+++ b/.github/workflows/smoke-service-ports.lock.yml
@@ -882,6 +882,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1154,4 +1162,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/smoke-temporary-id.lock.yml b/.github/workflows/smoke-temporary-id.lock.yml
index 6a468ee3ff2..8fc72a33f79 100644
--- a/.github/workflows/smoke-temporary-id.lock.yml
+++ b/.github/workflows/smoke-temporary-id.lock.yml
@@ -958,6 +958,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1235,4 +1243,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/smoke-test-tools.lock.yml b/.github/workflows/smoke-test-tools.lock.yml
index 2085a057bf0..b4ea925c0c3 100644
--- a/.github/workflows/smoke-test-tools.lock.yml
+++ b/.github/workflows/smoke-test-tools.lock.yml
@@ -919,6 +919,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1194,4 +1202,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/smoke-update-cross-repo-pr.lock.yml b/.github/workflows/smoke-update-cross-repo-pr.lock.yml
index 5e9e3e03cc5..6dfa95029a0 100644
--- a/.github/workflows/smoke-update-cross-repo-pr.lock.yml
+++ b/.github/workflows/smoke-update-cross-repo-pr.lock.yml
@@ -1013,6 +1013,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1326,6 +1334,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/smoke-workflow-call-with-inputs.lock.yml b/.github/workflows/smoke-workflow-call-with-inputs.lock.yml
index ff0884963c3..aca80dcc956 100644
--- a/.github/workflows/smoke-workflow-call-with-inputs.lock.yml
+++ b/.github/workflows/smoke-workflow-call-with-inputs.lock.yml
@@ -918,6 +918,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1188,4 +1196,12 @@ jobs:
name: ${{ needs.activation.outputs.artifact_prefix }}safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/smoke-workflow-call.lock.yml b/.github/workflows/smoke-workflow-call.lock.yml
index b25f62ff38f..abdb242b659 100644
--- a/.github/workflows/smoke-workflow-call.lock.yml
+++ b/.github/workflows/smoke-workflow-call.lock.yml
@@ -909,6 +909,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1182,4 +1190,12 @@ jobs:
name: ${{ needs.activation.outputs.artifact_prefix }}safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/stale-repo-identifier.lock.yml b/.github/workflows/stale-repo-identifier.lock.yml
index 30ad5308879..49cc11d7496 100644
--- a/.github/workflows/stale-repo-identifier.lock.yml
+++ b/.github/workflows/stale-repo-identifier.lock.yml
@@ -1017,6 +1017,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1255,6 +1263,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml
index 8975fd3e943..d9dcb51ff32 100644
--- a/.github/workflows/static-analysis-report.lock.yml
+++ b/.github/workflows/static-analysis-report.lock.yml
@@ -1037,6 +1037,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1288,6 +1296,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/step-name-alignment.lock.yml b/.github/workflows/step-name-alignment.lock.yml
index f0ef80ece69..57fbe8997bc 100644
--- a/.github/workflows/step-name-alignment.lock.yml
+++ b/.github/workflows/step-name-alignment.lock.yml
@@ -959,6 +959,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1211,6 +1219,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/sub-issue-closer.lock.yml b/.github/workflows/sub-issue-closer.lock.yml
index f0b61a85939..93fd46e0f93 100644
--- a/.github/workflows/sub-issue-closer.lock.yml
+++ b/.github/workflows/sub-issue-closer.lock.yml
@@ -891,6 +891,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1130,4 +1138,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml
index 359b54b8e62..c721244f848 100644
--- a/.github/workflows/super-linter.lock.yml
+++ b/.github/workflows/super-linter.lock.yml
@@ -905,6 +905,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1142,6 +1150,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
super_linter:
needs: activation
diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml
index e5c885a5120..3a80d9127e0 100644
--- a/.github/workflows/technical-doc-writer.lock.yml
+++ b/.github/workflows/technical-doc-writer.lock.yml
@@ -1092,6 +1092,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1518,6 +1526,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/terminal-stylist.lock.yml b/.github/workflows/terminal-stylist.lock.yml
index 66b4d96a3d0..fcb6eb20e81 100644
--- a/.github/workflows/terminal-stylist.lock.yml
+++ b/.github/workflows/terminal-stylist.lock.yml
@@ -914,6 +914,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1150,4 +1158,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/test-create-pr-error-handling.lock.yml b/.github/workflows/test-create-pr-error-handling.lock.yml
index 720bd648a43..814cd8cafff 100644
--- a/.github/workflows/test-create-pr-error-handling.lock.yml
+++ b/.github/workflows/test-create-pr-error-handling.lock.yml
@@ -946,6 +946,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1229,6 +1237,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/test-dispatcher.lock.yml b/.github/workflows/test-dispatcher.lock.yml
index c64d1d0cc74..f12d952e618 100644
--- a/.github/workflows/test-dispatcher.lock.yml
+++ b/.github/workflows/test-dispatcher.lock.yml
@@ -830,6 +830,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1064,4 +1072,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/test-project-url-default.lock.yml b/.github/workflows/test-project-url-default.lock.yml
index 6ecdb0e6941..fe6b1951fb8 100644
--- a/.github/workflows/test-project-url-default.lock.yml
+++ b/.github/workflows/test-project-url-default.lock.yml
@@ -890,6 +890,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1127,4 +1135,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml
index 224cfe39193..8b4037f3002 100644
--- a/.github/workflows/tidy.lock.yml
+++ b/.github/workflows/tidy.lock.yml
@@ -1005,6 +1005,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1319,6 +1327,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/token-logs-fetch.lock.yml b/.github/workflows/token-logs-fetch.lock.yml
index 91782040481..a18cf2108e3 100644
--- a/.github/workflows/token-logs-fetch.lock.yml
+++ b/.github/workflows/token-logs-fetch.lock.yml
@@ -894,6 +894,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1133,6 +1141,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml
index 3e3c40e0ae2..40fa217dfe9 100644
--- a/.github/workflows/typist.lock.yml
+++ b/.github/workflows/typist.lock.yml
@@ -987,6 +987,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1238,4 +1246,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/ubuntu-image-analyzer.lock.yml b/.github/workflows/ubuntu-image-analyzer.lock.yml
index 19bf3e37f0c..6f70a78b230 100644
--- a/.github/workflows/ubuntu-image-analyzer.lock.yml
+++ b/.github/workflows/ubuntu-image-analyzer.lock.yml
@@ -899,6 +899,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1213,6 +1221,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml
index 8e03e4c4cff..8940f6dc9d6 100644
--- a/.github/workflows/unbloat-docs.lock.yml
+++ b/.github/workflows/unbloat-docs.lock.yml
@@ -1260,6 +1260,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/notify_comment_error.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1660,6 +1668,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/update-astro.lock.yml b/.github/workflows/update-astro.lock.yml
index 34469ec37f9..67eb5d0628a 100644
--- a/.github/workflows/update-astro.lock.yml
+++ b/.github/workflows/update-astro.lock.yml
@@ -924,6 +924,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1238,6 +1246,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml
index 8f5474e67b5..773bb5aa68e 100644
--- a/.github/workflows/video-analyzer.lock.yml
+++ b/.github/workflows/video-analyzer.lock.yml
@@ -884,6 +884,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1121,4 +1129,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/weekly-blog-post-writer.lock.yml b/.github/workflows/weekly-blog-post-writer.lock.yml
index 880e266f62a..d44753cbe2b 100644
--- a/.github/workflows/weekly-blog-post-writer.lock.yml
+++ b/.github/workflows/weekly-blog-post-writer.lock.yml
@@ -1063,6 +1063,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1498,6 +1506,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/weekly-editors-health-check.lock.yml b/.github/workflows/weekly-editors-health-check.lock.yml
index b650c986bfb..ede2b3f56ed 100644
--- a/.github/workflows/weekly-editors-health-check.lock.yml
+++ b/.github/workflows/weekly-editors-health-check.lock.yml
@@ -932,6 +932,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1201,6 +1209,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml
index 9f51dc26a55..46838bd5325 100644
--- a/.github/workflows/weekly-issue-summary.lock.yml
+++ b/.github/workflows/weekly-issue-summary.lock.yml
@@ -934,6 +934,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1171,6 +1179,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
update_cache_memory:
needs:
diff --git a/.github/workflows/weekly-safe-outputs-spec-review.lock.yml b/.github/workflows/weekly-safe-outputs-spec-review.lock.yml
index 409165719ac..15d111b7f62 100644
--- a/.github/workflows/weekly-safe-outputs-spec-review.lock.yml
+++ b/.github/workflows/weekly-safe-outputs-spec-review.lock.yml
@@ -866,6 +866,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1135,6 +1143,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
- name: Restore actions folder
if: always()
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
diff --git a/.github/workflows/workflow-generator.lock.yml b/.github/workflows/workflow-generator.lock.yml
index 00526e52cdc..7da2df8943b 100644
--- a/.github/workflows/workflow-generator.lock.yml
+++ b/.github/workflows/workflow-generator.lock.yml
@@ -940,6 +940,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1246,6 +1254,14 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
unlock:
needs:
diff --git a/.github/workflows/workflow-health-manager.lock.yml b/.github/workflows/workflow-health-manager.lock.yml
index ec6656127f5..6d35d609aa7 100644
--- a/.github/workflows/workflow-health-manager.lock.yml
+++ b/.github/workflows/workflow-health-manager.lock.yml
@@ -973,6 +973,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1331,4 +1339,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/workflow-normalizer.lock.yml b/.github/workflows/workflow-normalizer.lock.yml
index 771065ff964..ad1694f361a 100644
--- a/.github/workflows/workflow-normalizer.lock.yml
+++ b/.github/workflows/workflow-normalizer.lock.yml
@@ -934,6 +934,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1172,4 +1180,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/.github/workflows/workflow-skill-extractor.lock.yml b/.github/workflows/workflow-skill-extractor.lock.yml
index 42b29421339..d7e8eea5470 100644
--- a/.github/workflows/workflow-skill-extractor.lock.yml
+++ b/.github/workflows/workflow-skill-extractor.lock.yml
@@ -905,6 +905,14 @@ jobs:
setupGlobals(core, github, context, exec, io);
const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
await main();
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
detection:
needs: agent
@@ -1143,4 +1151,12 @@ jobs:
name: safe-output-items
path: /tmp/gh-aw/safe-output-items.jsonl
if-no-files-found: ignore
+ - name: Send OTLP job span
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
+ with:
+ script: |
+ const { sendJobConclusionSpan } = require('${{ runner.temp }}/gh-aw/actions/send_otlp_span.cjs');
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
diff --git a/actions/setup/js/generate_observability_summary.cjs b/actions/setup/js/generate_observability_summary.cjs
index 0f28bb12a48..ae45457929e 100644
--- a/actions/setup/js/generate_observability_summary.cjs
+++ b/actions/setup/js/generate_observability_summary.cjs
@@ -124,6 +124,15 @@ async function main(core) {
const markdown = buildObservabilitySummary(data);
await core.summary.addRaw(markdown).write();
core.info("Generated observability summary in step summary");
+
+ // Send an OTLP conclusion span to the configured endpoint, if any.
+ // Non-fatal: errors are handled inside sendJobConclusionSpan via console.warn.
+ try {
+ const { sendJobConclusionSpan } = require("./send_otlp_span.cjs");
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
+ } catch {
+ // Silently ignore unexpected require/call failures.
+ }
}
module.exports = {
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
index 1a75a9eb202..70f50db038d 100644
--- a/actions/setup/js/send_otlp_span.cjs
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -2,6 +2,7 @@
///
const { randomBytes } = require("crypto");
+const fs = require("fs");
/**
* send_otlp_span.cjs
@@ -73,12 +74,13 @@ function buildAttr(key, value) {
/**
* @typedef {Object} OTLPSpanOptions
- * @property {string} traceId - 32-char hex trace ID
- * @property {string} spanId - 16-char hex span ID
- * @property {string} spanName - Human-readable span name
- * @property {number} startMs - Span start time (ms since epoch)
- * @property {number} endMs - Span end time (ms since epoch)
- * @property {string} serviceName - Value for the service.name resource attribute
+ * @property {string} traceId - 32-char hex trace ID
+ * @property {string} spanId - 16-char hex span ID
+ * @property {string} spanName - Human-readable span name
+ * @property {number} startMs - Span start time (ms since epoch)
+ * @property {number} endMs - Span end time (ms since epoch)
+ * @property {string} serviceName - Value for the service.name resource attribute
+ * @property {string} [scopeVersion] - gh-aw version string (e.g. from GH_AW_INFO_VERSION)
* @property {Array<{key: string, value: object}>} attributes - Span attributes
*/
@@ -88,7 +90,7 @@ function buildAttr(key, value) {
* @param {OTLPSpanOptions} opts
* @returns {object} - Ready to be serialised as JSON and POSTed to `/v1/traces`
*/
-function buildOTLPPayload({ traceId, spanId, spanName, startMs, endMs, serviceName, attributes }) {
+function buildOTLPPayload({ traceId, spanId, spanName, startMs, endMs, serviceName, scopeVersion, attributes }) {
return {
resourceSpans: [
{
@@ -97,7 +99,7 @@ function buildOTLPPayload({ traceId, spanId, spanName, startMs, endMs, serviceNa
},
scopeSpans: [
{
- scope: { name: "gh-aw.setup", version: "1.0.0" },
+ scope: { name: "gh-aw", version: scopeVersion || "unknown" },
spans: [
{
traceId,
@@ -122,22 +124,47 @@ function buildOTLPPayload({ traceId, spanId, spanName, startMs, endMs, serviceNa
// ---------------------------------------------------------------------------
/**
- * POST an OTLP traces payload to `{endpoint}/v1/traces`.
+ * POST an OTLP traces payload to `{endpoint}/v1/traces` with automatic retries.
*
- * @param {string} endpoint - OTLP base URL (e.g. https://traces.example.com:4317)
- * @param {object} payload - Serialisable OTLP JSON object
+ * Failures are surfaced as `console.warn` messages and never thrown; OTLP
+ * export failures must not break the workflow. Uses exponential back-off
+ * between attempts (100 ms, 200 ms) so the three total attempts finish in
+ * well under a second in the typical success case.
+ *
+ * @param {string} endpoint - OTLP base URL (e.g. https://traces.example.com:4317)
+ * @param {object} payload - Serialisable OTLP JSON object
+ * @param {{ maxRetries?: number, baseDelayMs?: number }} [opts]
* @returns {Promise}
- * @throws {Error} when the server returns a non-2xx status
*/
-async function sendOTLPSpan(endpoint, payload) {
+async function sendOTLPSpan(endpoint, payload, { maxRetries = 2, baseDelayMs = 100 } = {}) {
const url = endpoint.replace(/\/$/, "") + "/v1/traces";
- const response = await fetch(url, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(payload),
- });
- if (!response.ok) {
- throw new Error(`OTLP export failed: HTTP ${response.status} ${response.statusText}`);
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
+ if (attempt > 0) {
+ await new Promise(resolve => setTimeout(resolve, baseDelayMs * 2 ** (attempt - 1)));
+ }
+ try {
+ const response = await fetch(url, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload),
+ });
+ if (response.ok) {
+ return;
+ }
+ const msg = `HTTP ${response.status} ${response.statusText}`;
+ if (attempt < maxRetries) {
+ console.warn(`OTLP export attempt ${attempt + 1}/${maxRetries + 1} failed: ${msg}, retrying…`);
+ } else {
+ console.warn(`OTLP export failed after ${maxRetries + 1} attempts: ${msg}`);
+ }
+ } catch (err) {
+ const msg = err instanceof Error ? err.message : String(err);
+ if (attempt < maxRetries) {
+ console.warn(`OTLP export attempt ${attempt + 1}/${maxRetries + 1} error: ${msg}, retrying…`);
+ } else {
+ console.warn(`OTLP export error after ${maxRetries + 1} attempts: ${msg}`);
+ }
+ }
}
}
@@ -238,6 +265,7 @@ async function sendJobSetupSpan(options = {}) {
startMs,
endMs,
serviceName,
+ scopeVersion: process.env.GH_AW_INFO_VERSION || "unknown",
attributes,
});
@@ -245,6 +273,105 @@ async function sendJobSetupSpan(options = {}) {
return traceId;
}
+// ---------------------------------------------------------------------------
+// Utilities for conclusion span
+// ---------------------------------------------------------------------------
+
+/**
+ * Safely read and parse a JSON file. Returns `null` on any error (missing
+ * file, invalid JSON, permission denied, etc.).
+ *
+ * @param {string} filePath - Absolute path to the JSON file
+ * @returns {object | null}
+ */
+function readJSONIfExists(filePath) {
+ try {
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
+ } catch {
+ return null;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// High-level: job conclusion span
+// ---------------------------------------------------------------------------
+
+/**
+ * Send a conclusion span for a safe_outputs or conclusion job to the configured
+ * OTLP endpoint. The span carries workflow metadata read from `aw_info.json`
+ * and the effective token count from `GH_AW_EFFECTIVE_TOKENS`.
+ *
+ * This is a no-op when `OTEL_EXPORTER_OTLP_ENDPOINT` is not set. All errors
+ * are surfaced as `console.warn` messages and never re-thrown.
+ *
+ * Environment variables consumed:
+ * - `OTEL_EXPORTER_OTLP_ENDPOINT` – collector endpoint
+ * - `OTEL_SERVICE_NAME` – service name (defaults to "gh-aw")
+ * - `GH_AW_EFFECTIVE_TOKENS` – total effective token count for the run
+ * - `GITHUB_RUN_ID` – GitHub Actions run ID
+ * - `GITHUB_ACTOR` – GitHub Actions actor
+ * - `GITHUB_REPOSITORY` – `owner/repo` string
+ *
+ * Runtime files read:
+ * - `/tmp/gh-aw/aw_info.json` – workflow/engine metadata written by the agent job
+ *
+ * @param {string} spanName - OTLP span name (e.g. `"gh-aw.job.safe-outputs"`)
+ * @param {{ startMs?: number }} [options]
+ * @returns {Promise}
+ */
+async function sendJobConclusionSpan(spanName, options = {}) {
+ const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "";
+ if (!endpoint) {
+ return;
+ }
+
+ const startMs = options.startMs ?? Date.now();
+
+ // Read workflow metadata from aw_info.json (written by the agent job setup step).
+ const awInfo = readJSONIfExists("/tmp/gh-aw/aw_info.json") || {};
+
+ // Effective token count is surfaced by the agent job and passed to downstream jobs
+ // via the GH_AW_EFFECTIVE_TOKENS environment variable.
+ const rawET = process.env.GH_AW_EFFECTIVE_TOKENS || "";
+ const effectiveTokens = rawET ? parseInt(rawET, 10) : NaN;
+
+ const serviceName = process.env.OTEL_SERVICE_NAME || "gh-aw";
+ const version = awInfo.agent_version || awInfo.version || process.env.GH_AW_INFO_VERSION || "unknown";
+
+ // Use the workflow_call_id from aw_info as the trace ID when available so that
+ // conclusion spans can be correlated with the activation span.
+ const awTraceId = typeof awInfo.context?.workflow_call_id === "string" ? awInfo.context.workflow_call_id.replace(/-/g, "") : "";
+ const traceId = awTraceId && isValidTraceId(awTraceId) ? awTraceId : generateTraceId();
+
+ const workflowName = awInfo.workflow_name || "";
+ const engineId = awInfo.engine_id || "";
+ const model = awInfo.model || "";
+ const runId = process.env.GITHUB_RUN_ID || "";
+ const actor = process.env.GITHUB_ACTOR || "";
+ const repository = process.env.GITHUB_REPOSITORY || "";
+
+ const attributes = [buildAttr("gh-aw.workflow.name", workflowName), buildAttr("gh-aw.run.id", runId), buildAttr("gh-aw.run.actor", actor), buildAttr("gh-aw.repository", repository)];
+
+ if (engineId) attributes.push(buildAttr("gh-aw.engine.id", engineId));
+ if (model) attributes.push(buildAttr("gh-aw.model", model));
+ if (!isNaN(effectiveTokens) && effectiveTokens > 0) {
+ attributes.push(buildAttr("gh-aw.effective_tokens", effectiveTokens));
+ }
+
+ const payload = buildOTLPPayload({
+ traceId,
+ spanId: generateSpanId(),
+ spanName,
+ startMs,
+ endMs: Date.now(),
+ serviceName,
+ scopeVersion: version,
+ attributes,
+ });
+
+ await sendOTLPSpan(endpoint, payload);
+}
+
module.exports = {
isValidTraceId,
generateTraceId,
@@ -253,5 +380,7 @@ module.exports = {
buildAttr,
buildOTLPPayload,
sendOTLPSpan,
+ readJSONIfExists,
sendJobSetupSpan,
+ sendJobConclusionSpan,
};
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index 7853b1f653a..681529e2a93 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -4,7 +4,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
// Module import
// ---------------------------------------------------------------------------
-const { isValidTraceId, generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, sendOTLPSpan, sendJobSetupSpan } = await import("./send_otlp_span.cjs");
+const { isValidTraceId, generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, sendOTLPSpan, sendJobSetupSpan, sendJobConclusionSpan } = await import("./send_otlp_span.cjs");
// ---------------------------------------------------------------------------
// isValidTraceId
@@ -128,6 +128,7 @@ describe("buildOTLPPayload", () => {
startMs: 1000,
endMs: 2000,
serviceName: "gh-aw",
+ scopeVersion: "v1.2.3",
attributes: [buildAttr("foo", "bar")],
});
@@ -137,9 +138,10 @@ describe("buildOTLPPayload", () => {
// Resource
expect(rs.resource.attributes).toContainEqual({ key: "service.name", value: { stringValue: "gh-aw" } });
- // Scope
+ // Scope — name is always "gh-aw"; version comes from scopeVersion
expect(rs.scopeSpans).toHaveLength(1);
- expect(rs.scopeSpans[0].scope.name).toBe("gh-aw.setup");
+ expect(rs.scopeSpans[0].scope.name).toBe("gh-aw");
+ expect(rs.scopeSpans[0].scope.version).toBe("v1.2.3");
// Span
const span = rs.scopeSpans[0].spans[0];
@@ -152,6 +154,19 @@ describe("buildOTLPPayload", () => {
expect(span.status.code).toBe(1);
expect(span.attributes).toContainEqual({ key: "foo", value: { stringValue: "bar" } });
});
+
+ it("uses 'unknown' as scope version when scopeVersion is omitted", () => {
+ const payload = buildOTLPPayload({
+ traceId: "a".repeat(32),
+ spanId: "b".repeat(16),
+ spanName: "test",
+ startMs: 0,
+ endMs: 1,
+ serviceName: "gh-aw",
+ attributes: [],
+ });
+ expect(payload.resourceSpans[0].scopeSpans[0].scope.version).toBe("unknown");
+ });
});
// ---------------------------------------------------------------------------
@@ -191,11 +206,48 @@ describe("sendOTLPSpan", () => {
expect(url).toBe("https://traces.example.com/v1/traces");
});
- it("throws when server returns non-2xx status", async () => {
+ it("warns (does not throw) when server returns non-2xx status on all retries", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: false, status: 400, statusText: "Bad Request" });
vi.stubGlobal("fetch", mockFetch);
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
+
+ // Should not throw
+ await expect(sendOTLPSpan("https://traces.example.com", {}, { maxRetries: 1, baseDelayMs: 1 })).resolves.toBeUndefined();
- await expect(sendOTLPSpan("https://traces.example.com", {})).rejects.toThrow("OTLP export failed: HTTP 400 Bad Request");
+ // Two attempts (1 initial + 1 retry)
+ expect(mockFetch).toHaveBeenCalledTimes(2);
+ expect(warnSpy).toHaveBeenCalledTimes(2);
+ expect(warnSpy.mock.calls[0][0]).toContain("attempt 1/2 failed");
+ expect(warnSpy.mock.calls[1][0]).toContain("failed after 2 attempts");
+
+ warnSpy.mockRestore();
+ });
+
+ it("retries on failure and succeeds on second attempt", async () => {
+ const mockFetch = vi.fn().mockResolvedValueOnce({ ok: false, status: 503, statusText: "Service Unavailable" }).mockResolvedValueOnce({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
+
+ await sendOTLPSpan("https://traces.example.com", {}, { maxRetries: 2, baseDelayMs: 1 });
+
+ expect(mockFetch).toHaveBeenCalledTimes(2);
+ expect(warnSpy).toHaveBeenCalledTimes(1);
+ expect(warnSpy.mock.calls[0][0]).toContain("attempt 1/3 failed");
+
+ warnSpy.mockRestore();
+ });
+
+ it("warns (does not throw) when fetch rejects on all retries", async () => {
+ const mockFetch = vi.fn().mockRejectedValue(new Error("network error"));
+ vi.stubGlobal("fetch", mockFetch);
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
+
+ await expect(sendOTLPSpan("https://traces.example.com", {}, { maxRetries: 1, baseDelayMs: 1 })).resolves.toBeUndefined();
+
+ expect(mockFetch).toHaveBeenCalledTimes(2);
+ expect(warnSpy.mock.calls[1][0]).toContain("error after 2 attempts");
+
+ warnSpy.mockRestore();
});
});
@@ -393,3 +445,99 @@ describe("sendJobSetupSpan", () => {
expect(keys).not.toContain("gh-aw.engine.id");
});
});
+
+// ---------------------------------------------------------------------------
+// sendJobConclusionSpan
+// ---------------------------------------------------------------------------
+
+describe("sendJobConclusionSpan", () => {
+ /** @type {Record} */
+ const savedEnv = {};
+ const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "GH_AW_EFFECTIVE_TOKENS", "GH_AW_INFO_VERSION", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
+
+ beforeEach(() => {
+ vi.stubGlobal("fetch", vi.fn());
+ for (const k of envKeys) {
+ savedEnv[k] = process.env[k];
+ delete process.env[k];
+ }
+ });
+
+ afterEach(() => {
+ vi.unstubAllGlobals();
+ for (const k of envKeys) {
+ if (savedEnv[k] !== undefined) {
+ process.env[k] = savedEnv[k];
+ } else {
+ delete process.env[k];
+ }
+ }
+ });
+
+ it("is a no-op when OTEL_EXPORTER_OTLP_ENDPOINT is not set", async () => {
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
+ expect(fetch).not.toHaveBeenCalled();
+ });
+
+ it("sends a span with the given span name", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ process.env.GITHUB_RUN_ID = "111";
+ process.env.GITHUB_ACTOR = "octocat";
+ process.env.GITHUB_REPOSITORY = "owner/repo";
+
+ await sendJobConclusionSpan("gh-aw.job.safe-outputs");
+
+ expect(mockFetch).toHaveBeenCalledOnce();
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ const span = body.resourceSpans[0].scopeSpans[0].spans[0];
+ expect(span.name).toBe("gh-aw.job.safe-outputs");
+ expect(span.traceId).toMatch(/^[0-9a-f]{32}$/);
+ expect(span.spanId).toMatch(/^[0-9a-f]{16}$/);
+ });
+
+ it("includes effective_tokens attribute when GH_AW_EFFECTIVE_TOKENS is set", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ process.env.GH_AW_EFFECTIVE_TOKENS = "5000";
+
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
+
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ const span = body.resourceSpans[0].scopeSpans[0].spans[0];
+ const etAttr = span.attributes.find(a => a.key === "gh-aw.effective_tokens");
+ expect(etAttr).toBeDefined();
+ expect(etAttr.value.intValue).toBe(5000);
+ });
+
+ it("omits effective_tokens attribute when GH_AW_EFFECTIVE_TOKENS is absent", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
+
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ const span = body.resourceSpans[0].scopeSpans[0].spans[0];
+ const keys = span.attributes.map(a => a.key);
+ expect(keys).not.toContain("gh-aw.effective_tokens");
+ });
+
+ it("uses GH_AW_INFO_VERSION as scope version when aw_info.json is absent", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ process.env.GH_AW_INFO_VERSION = "v2.0.0";
+
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
+
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ expect(body.resourceSpans[0].scopeSpans[0].scope.version).toBe("v2.0.0");
+ });
+});
diff --git a/pkg/workflow/compiler_safe_outputs_job.go b/pkg/workflow/compiler_safe_outputs_job.go
index 3f589834a70..7c25971ce48 100644
--- a/pkg/workflow/compiler_safe_outputs_job.go
+++ b/pkg/workflow/compiler_safe_outputs_job.go
@@ -379,6 +379,9 @@ func (c *Compiler) buildConsolidatedSafeOutputsJob(data *WorkflowData, mainJobNa
steps = append(steps, buildSafeOutputItemsManifestUploadStep(agentArtifactPrefix)...)
}
+ // Append OTLP conclusion span step (no-op when endpoint is not configured).
+ steps = append(steps, generateOTLPConclusionSpanStep("gh-aw.job.safe-outputs"))
+
// In dev mode the setup action is referenced via a local path (./actions/setup), so its files
// live in the workspace. When the safe_outputs job contains a checkout step for
// create_pull_request or push_to_pull_request_branch, the workspace is replaced with the
diff --git a/pkg/workflow/notify_comment.go b/pkg/workflow/notify_comment.go
index 67a96f075a5..5d15dc1e1af 100644
--- a/pkg/workflow/notify_comment.go
+++ b/pkg/workflow/notify_comment.go
@@ -354,6 +354,9 @@ func (c *Compiler) buildConclusionJob(data *WorkflowData, mainJobName string, sa
steps = append(steps, c.buildGitHubAppTokenInvalidationStep()...)
}
+ // Append OTLP conclusion span step (no-op when endpoint is not configured).
+ steps = append(steps, generateOTLPConclusionSpanStep("gh-aw.job.conclusion"))
+
// Build the condition for this job:
// 1. always() - run even if agent fails
// 2. agent was activated (not skipped) OR lockdown check failed in activation job
diff --git a/pkg/workflow/observability_otlp.go b/pkg/workflow/observability_otlp.go
index e5eb0a29c32..f0af75dede7 100644
--- a/pkg/workflow/observability_otlp.go
+++ b/pkg/workflow/observability_otlp.go
@@ -48,8 +48,28 @@ func getOTLPEndpointEnvValue(config *FrontmatterConfig) string {
return config.Observability.OTLP.Endpoint
}
-// injectOTLPConfig modifies workflowData to incorporate any OTLP configuration:
+// generateOTLPConclusionSpanStep generates a GitHub Actions step that sends an OTLP
+// conclusion span from a downstream job (safe_outputs or conclusion).
//
+// The step is a no-op when OTEL_EXPORTER_OTLP_ENDPOINT is not set, so it is safe to
+// emit unconditionally. It runs with if: always() and continue-on-error: true so OTLP
+// failures can never block the job.
+//
+// Parameters:
+// - spanName: the OTLP span name, e.g. "gh-aw.job.safe-outputs"
+func generateOTLPConclusionSpanStep(spanName string) string {
+ var sb strings.Builder
+ sb.WriteString(" - name: Send OTLP job span\n")
+ sb.WriteString(" if: always()\n")
+ sb.WriteString(" continue-on-error: true\n")
+ fmt.Fprintf(&sb, " uses: %s\n", GetActionPin("actions/github-script"))
+ sb.WriteString(" with:\n")
+ sb.WriteString(" script: |\n")
+ fmt.Fprintf(&sb, " const { sendJobConclusionSpan } = require('%s/send_otlp_span.cjs');\n", SetupActionDestination)
+ fmt.Fprintf(&sb, " await sendJobConclusionSpan(%q);\n", spanName)
+ return sb.String()
+}
+
// 1. When the endpoint is a static URL, its hostname is appended to
// NetworkPermissions.Allowed so the AWF firewall allows outbound traffic to it.
//
diff --git a/pkg/workflow/observability_otlp_test.go b/pkg/workflow/observability_otlp_test.go
index fbdc52931cc..3e4535a1850 100644
--- a/pkg/workflow/observability_otlp_test.go
+++ b/pkg/workflow/observability_otlp_test.go
@@ -330,3 +330,22 @@ func TestObservabilityConfigParsing(t *testing.T) {
})
}
}
+
+// TestGenerateOTLPConclusionSpanStep verifies the YAML produced for OTLP conclusion span steps.
+func TestGenerateOTLPConclusionSpanStep(t *testing.T) {
+ t.Run("safe-outputs span name", func(t *testing.T) {
+ step := generateOTLPConclusionSpanStep("gh-aw.job.safe-outputs")
+ assert.Contains(t, step, "name: Send OTLP job span", "step should have correct name")
+ assert.Contains(t, step, "if: always()", "step should always run")
+ assert.Contains(t, step, "continue-on-error: true", "step should be non-fatal")
+ assert.Contains(t, step, "actions/github-script", "step should use github-script action")
+ assert.Contains(t, step, "sendJobConclusionSpan", "script should call sendJobConclusionSpan")
+ assert.Contains(t, step, "gh-aw.job.safe-outputs", "script should use the given span name")
+ assert.Contains(t, step, "send_otlp_span.cjs", "script should require send_otlp_span.cjs")
+ })
+
+ t.Run("conclusion span name", func(t *testing.T) {
+ step := generateOTLPConclusionSpanStep("gh-aw.job.conclusion")
+ assert.Contains(t, step, "gh-aw.job.conclusion", "script should use the given span name")
+ })
+}
From 0b4b16eae4269f79ff0787bbb60f6073d0ef18d1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 07:45:12 +0000
Subject: [PATCH 09/16] feat: add OTEL_EXPORTER_OTLP_HEADERS support to
observability.otlp config
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/8f5dc8d2-75f6-4186-affe-e329b01b1aaf
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/js/send_otlp_span.cjs | 34 +++++++-
actions/setup/js/send_otlp_span.test.cjs | 87 +++++++++++++++++++-
pkg/parser/schemas/main_workflow_schema.json | 4 +
pkg/workflow/frontmatter_types.go | 6 ++
pkg/workflow/observability_otlp.go | 10 +++
pkg/workflow/observability_otlp_test.go | 75 +++++++++++++++++
6 files changed, 214 insertions(+), 2 deletions(-)
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
index 70f50db038d..e835ba83229 100644
--- a/actions/setup/js/send_otlp_span.cjs
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -123,6 +123,32 @@ function buildOTLPPayload({ traceId, spanId, spanName, startMs, endMs, serviceNa
// HTTP transport
// ---------------------------------------------------------------------------
+/**
+ * Parse an `OTEL_EXPORTER_OTLP_HEADERS` value into a plain object suitable for
+ * merging into a `Headers` / `fetch` `headers` option.
+ *
+ * The value follows the OpenTelemetry specification:
+ * key=value[,key=value...]
+ * where individual keys and values may be percent-encoded.
+ * Empty pairs (from leading/trailing/consecutive commas) are silently skipped.
+ *
+ * @param {string} raw - Raw header string (e.g. "Authorization=Bearer tok,X-Tenant=acme")
+ * @returns {Record} Parsed headers object
+ */
+function parseOTLPHeaders(raw) {
+ if (!raw || !raw.trim()) return {};
+ /** @type {Record} */
+ const result = {};
+ for (const pair of raw.split(",")) {
+ const eqIdx = pair.indexOf("=");
+ if (eqIdx <= 0) continue; // skip empty keys or malformed pairs
+ const key = decodeURIComponent(pair.slice(0, eqIdx).trim());
+ const value = decodeURIComponent(pair.slice(eqIdx + 1).trim());
+ if (key) result[key] = value;
+ }
+ return result;
+}
+
/**
* POST an OTLP traces payload to `{endpoint}/v1/traces` with automatic retries.
*
@@ -131,6 +157,9 @@ function buildOTLPPayload({ traceId, spanId, spanName, startMs, endMs, serviceNa
* between attempts (100 ms, 200 ms) so the three total attempts finish in
* well under a second in the typical success case.
*
+ * Reads `OTEL_EXPORTER_OTLP_HEADERS` from the environment and merges any
+ * configured headers into every request.
+ *
* @param {string} endpoint - OTLP base URL (e.g. https://traces.example.com:4317)
* @param {object} payload - Serialisable OTLP JSON object
* @param {{ maxRetries?: number, baseDelayMs?: number }} [opts]
@@ -138,6 +167,8 @@ function buildOTLPPayload({ traceId, spanId, spanName, startMs, endMs, serviceNa
*/
async function sendOTLPSpan(endpoint, payload, { maxRetries = 2, baseDelayMs = 100 } = {}) {
const url = endpoint.replace(/\/$/, "") + "/v1/traces";
+ const extraHeaders = parseOTLPHeaders(process.env.OTEL_EXPORTER_OTLP_HEADERS || "");
+ const headers = { "Content-Type": "application/json", ...extraHeaders };
for (let attempt = 0; attempt <= maxRetries; attempt++) {
if (attempt > 0) {
await new Promise(resolve => setTimeout(resolve, baseDelayMs * 2 ** (attempt - 1)));
@@ -145,7 +176,7 @@ async function sendOTLPSpan(endpoint, payload, { maxRetries = 2, baseDelayMs = 1
try {
const response = await fetch(url, {
method: "POST",
- headers: { "Content-Type": "application/json" },
+ headers,
body: JSON.stringify(payload),
});
if (response.ok) {
@@ -379,6 +410,7 @@ module.exports = {
toNanoString,
buildAttr,
buildOTLPPayload,
+ parseOTLPHeaders,
sendOTLPSpan,
readJSONIfExists,
sendJobSetupSpan,
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index 681529e2a93..cb22f29e54d 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -4,7 +4,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
// Module import
// ---------------------------------------------------------------------------
-const { isValidTraceId, generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, sendOTLPSpan, sendJobSetupSpan, sendJobConclusionSpan } = await import("./send_otlp_span.cjs");
+const { isValidTraceId, generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, parseOTLPHeaders, sendOTLPSpan, sendJobSetupSpan, sendJobConclusionSpan } = await import("./send_otlp_span.cjs");
// ---------------------------------------------------------------------------
// isValidTraceId
@@ -251,6 +251,91 @@ describe("sendOTLPSpan", () => {
});
});
+// ---------------------------------------------------------------------------
+// parseOTLPHeaders
+// ---------------------------------------------------------------------------
+
+describe("parseOTLPHeaders", () => {
+ it("returns empty object for empty/null/whitespace input", () => {
+ expect(parseOTLPHeaders("")).toEqual({});
+ expect(parseOTLPHeaders(" ")).toEqual({});
+ });
+
+ it("parses a single key=value pair", () => {
+ expect(parseOTLPHeaders("Authorization=Bearer mytoken")).toEqual({ Authorization: "Bearer mytoken" });
+ });
+
+ it("parses multiple comma-separated key=value pairs", () => {
+ expect(parseOTLPHeaders("X-Tenant=acme,X-Region=us-east-1")).toEqual({
+ "X-Tenant": "acme",
+ "X-Region": "us-east-1",
+ });
+ });
+
+ it("handles percent-encoded values", () => {
+ expect(parseOTLPHeaders("Authorization=Bearer%20tok%3Dvalue")).toEqual({ Authorization: "Bearer tok=value" });
+ });
+
+ it("handles values containing = signs (only first = is delimiter)", () => {
+ expect(parseOTLPHeaders("Authorization=Bearer base64==")).toEqual({ Authorization: "Bearer base64==" });
+ });
+
+ it("skips malformed pairs with no =", () => {
+ const result = parseOTLPHeaders("Valid=value,malformedNoEquals");
+ expect(result).toEqual({ Valid: "value" });
+ });
+
+ it("skips pairs with empty key", () => {
+ const result = parseOTLPHeaders("=value,Good=ok");
+ expect(result).toEqual({ Good: "ok" });
+ });
+});
+
+// ---------------------------------------------------------------------------
+// sendOTLPSpan headers
+// ---------------------------------------------------------------------------
+
+describe("sendOTLPSpan with OTEL_EXPORTER_OTLP_HEADERS", () => {
+ const savedHeaders = process.env.OTEL_EXPORTER_OTLP_HEADERS;
+
+ beforeEach(() => {
+ vi.stubGlobal("fetch", vi.fn());
+ delete process.env.OTEL_EXPORTER_OTLP_HEADERS;
+ });
+
+ afterEach(() => {
+ vi.unstubAllGlobals();
+ if (savedHeaders !== undefined) {
+ process.env.OTEL_EXPORTER_OTLP_HEADERS = savedHeaders;
+ } else {
+ delete process.env.OTEL_EXPORTER_OTLP_HEADERS;
+ }
+ });
+
+ it("includes custom headers when OTEL_EXPORTER_OTLP_HEADERS is set", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_HEADERS = "Authorization=Bearer mytoken,X-Tenant=acme";
+ await sendOTLPSpan("https://traces.example.com", {});
+
+ const [, init] = mockFetch.mock.calls[0];
+ expect(init.headers["Authorization"]).toBe("Bearer mytoken");
+ expect(init.headers["X-Tenant"]).toBe("acme");
+ expect(init.headers["Content-Type"]).toBe("application/json");
+ });
+
+ it("does not add extra headers when OTEL_EXPORTER_OTLP_HEADERS is absent", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ await sendOTLPSpan("https://traces.example.com", {});
+
+ const [, init] = mockFetch.mock.calls[0];
+ expect(Object.keys(init.headers)).toEqual(["Content-Type"]);
+ });
+});
+
// ---------------------------------------------------------------------------
// sendJobSetupSpan
// ---------------------------------------------------------------------------
diff --git a/pkg/parser/schemas/main_workflow_schema.json b/pkg/parser/schemas/main_workflow_schema.json
index 303db6db17d..e1080e20740 100644
--- a/pkg/parser/schemas/main_workflow_schema.json
+++ b/pkg/parser/schemas/main_workflow_schema.json
@@ -8336,6 +8336,10 @@
"endpoint": {
"type": "string",
"description": "OTLP collector endpoint URL (e.g. 'https://traces.example.com:4317'). Supports GitHub Actions expressions such as ${{ secrets.OTLP_ENDPOINT }}. When a static URL is provided, its hostname is automatically added to the network firewall allowlist."
+ },
+ "headers": {
+ "type": "string",
+ "description": "Comma-separated list of key=value HTTP headers to include with every OTLP export request (e.g. 'Authorization=Bearer '). Supports GitHub Actions expressions such as ${{ secrets.OTLP_HEADERS }}. Injected as the OTEL_EXPORTER_OTLP_HEADERS environment variable."
}
},
"additionalProperties": false
diff --git a/pkg/workflow/frontmatter_types.go b/pkg/workflow/frontmatter_types.go
index ca8c9afa3c8..e3609f9f7ff 100644
--- a/pkg/workflow/frontmatter_types.go
+++ b/pkg/workflow/frontmatter_types.go
@@ -124,6 +124,12 @@ type OTLPConfig struct {
// When a static URL is provided, its hostname is automatically added to the
// network firewall allowlist.
Endpoint string `json:"endpoint,omitempty"`
+
+ // Headers is a comma-separated list of key=value HTTP headers to include with
+ // every OTLP export request (e.g. "Authorization=Bearer ").
+ // Supports GitHub Actions expressions such as ${{ secrets.OTLP_HEADERS }}.
+ // Injected as the standard OTEL_EXPORTER_OTLP_HEADERS environment variable.
+ Headers string `json:"headers,omitempty"`
}
// ObservabilityConfig represents workflow observability options.
diff --git a/pkg/workflow/observability_otlp.go b/pkg/workflow/observability_otlp.go
index f0af75dede7..c1463e59cde 100644
--- a/pkg/workflow/observability_otlp.go
+++ b/pkg/workflow/observability_otlp.go
@@ -77,6 +77,9 @@ func generateOTLPConclusionSpanStep(spanName string) string {
// workflow-level env: YAML block (workflowData.Env) so they are available to
// every step in the generated GitHub Actions workflow.
//
+// 3. When headers are configured, OTEL_EXPORTER_OTLP_HEADERS is also appended
+// to the workflow-level env: block.
+//
// When no OTLP endpoint is configured the function is a no-op.
func (c *Compiler) injectOTLPConfig(workflowData *WorkflowData) {
endpoint := getOTLPEndpointEnvValue(workflowData.ParsedFrontmatter)
@@ -97,6 +100,13 @@ func (c *Compiler) injectOTLPConfig(workflowData *WorkflowData) {
// 2. Inject OTEL env vars into the workflow-level env: block.
otlpEnvLines := fmt.Sprintf(" OTEL_EXPORTER_OTLP_ENDPOINT: %s\n OTEL_SERVICE_NAME: gh-aw", endpoint)
+
+ // 3. Inject OTEL_EXPORTER_OTLP_HEADERS when configured.
+ if headers := workflowData.ParsedFrontmatter.Observability.OTLP.Headers; headers != "" {
+ otlpEnvLines += "\n OTEL_EXPORTER_OTLP_HEADERS: " + headers
+ otlpLog.Printf("Injected OTEL_EXPORTER_OTLP_HEADERS env var")
+ }
+
if workflowData.Env == "" {
workflowData.Env = "env:\n" + otlpEnvLines
} else {
diff --git a/pkg/workflow/observability_otlp_test.go b/pkg/workflow/observability_otlp_test.go
index 3e4535a1850..4fada70f060 100644
--- a/pkg/workflow/observability_otlp_test.go
+++ b/pkg/workflow/observability_otlp_test.go
@@ -247,6 +247,51 @@ func TestInjectOTLPConfig(t *testing.T) {
c.injectOTLPConfig(wd)
assert.Contains(t, wd.Env, "OTEL_SERVICE_NAME: gh-aw", "service name should always be gh-aw")
})
+
+ t.Run("injects OTEL_EXPORTER_OTLP_HEADERS when headers are configured", func(t *testing.T) {
+ c := newCompiler()
+ wd := &WorkflowData{
+ ParsedFrontmatter: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{
+ Endpoint: "https://traces.example.com",
+ Headers: "Authorization=Bearer tok,X-Tenant=acme",
+ },
+ },
+ },
+ }
+ c.injectOTLPConfig(wd)
+ assert.Contains(t, wd.Env, "OTEL_EXPORTER_OTLP_HEADERS: Authorization=Bearer tok,X-Tenant=acme", "headers var should be injected")
+ })
+
+ t.Run("injects OTEL_EXPORTER_OTLP_HEADERS for secret expression", func(t *testing.T) {
+ c := newCompiler()
+ wd := &WorkflowData{
+ ParsedFrontmatter: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{
+ Endpoint: "https://traces.example.com",
+ Headers: "${{ secrets.OTLP_HEADERS }}",
+ },
+ },
+ },
+ }
+ c.injectOTLPConfig(wd)
+ assert.Contains(t, wd.Env, "OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTLP_HEADERS }}", "headers var should support secret expressions")
+ })
+
+ t.Run("does not inject OTEL_EXPORTER_OTLP_HEADERS when headers not configured", func(t *testing.T) {
+ c := newCompiler()
+ wd := &WorkflowData{
+ ParsedFrontmatter: &FrontmatterConfig{
+ Observability: &ObservabilityConfig{
+ OTLP: &OTLPConfig{Endpoint: "https://traces.example.com"},
+ },
+ },
+ }
+ c.injectOTLPConfig(wd)
+ assert.NotContains(t, wd.Env, "OTEL_EXPORTER_OTLP_HEADERS", "headers var should not appear when unconfigured")
+ })
}
// TestObservabilityConfigParsing verifies that the OTLPConfig is correctly parsed
@@ -257,6 +302,7 @@ func TestObservabilityConfigParsing(t *testing.T) {
frontmatter map[string]any
wantOTLPConfig bool
expectedEndpoint string
+ expectedHeaders string
}{
{
name: "no observability section",
@@ -309,6 +355,34 @@ func TestObservabilityConfigParsing(t *testing.T) {
wantOTLPConfig: true,
expectedEndpoint: "https://traces.example.com",
},
+ {
+ name: "observability with otlp endpoint and headers",
+ frontmatter: map[string]any{
+ "observability": map[string]any{
+ "otlp": map[string]any{
+ "endpoint": "https://traces.example.com",
+ "headers": "Authorization=Bearer tok,X-Tenant=acme",
+ },
+ },
+ },
+ wantOTLPConfig: true,
+ expectedEndpoint: "https://traces.example.com",
+ expectedHeaders: "Authorization=Bearer tok,X-Tenant=acme",
+ },
+ {
+ name: "observability with otlp headers as secret expression",
+ frontmatter: map[string]any{
+ "observability": map[string]any{
+ "otlp": map[string]any{
+ "endpoint": "https://traces.example.com",
+ "headers": "${{ secrets.OTLP_HEADERS }}",
+ },
+ },
+ },
+ wantOTLPConfig: true,
+ expectedEndpoint: "https://traces.example.com",
+ expectedHeaders: "${{ secrets.OTLP_HEADERS }}",
+ },
}
for _, tt := range tests {
@@ -327,6 +401,7 @@ func TestObservabilityConfigParsing(t *testing.T) {
require.NotNil(t, config.Observability, "Observability should not be nil")
require.NotNil(t, config.Observability.OTLP, "OTLP should not be nil")
assert.Equal(t, tt.expectedEndpoint, config.Observability.OTLP.Endpoint, "Endpoint should match")
+ assert.Equal(t, tt.expectedHeaders, config.Observability.OTLP.Headers, "Headers should match")
})
}
}
From d3191e0964c101a51f9738692dfd1230a0077641 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 07:46:50 +0000
Subject: [PATCH 10/16] fix: decode before trim in parseOTLPHeaders, clarify
eqIdx comment
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/8f5dc8d2-75f6-4186-affe-e329b01b1aaf
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/js/send_otlp_span.cjs | 7 ++++---
actions/setup/js/send_otlp_span.test.cjs | 5 +++++
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
index e835ba83229..bf3f0655bd1 100644
--- a/actions/setup/js/send_otlp_span.cjs
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -141,9 +141,10 @@ function parseOTLPHeaders(raw) {
const result = {};
for (const pair of raw.split(",")) {
const eqIdx = pair.indexOf("=");
- if (eqIdx <= 0) continue; // skip empty keys or malformed pairs
- const key = decodeURIComponent(pair.slice(0, eqIdx).trim());
- const value = decodeURIComponent(pair.slice(eqIdx + 1).trim());
+ if (eqIdx <= 0) continue; // skip malformed pairs (no =) or empty keys (= at start)
+ // Decode before trimming so percent-encoded whitespace (%20) at edges is preserved correctly.
+ const key = decodeURIComponent(pair.slice(0, eqIdx)).trim();
+ const value = decodeURIComponent(pair.slice(eqIdx + 1)).trim();
if (key) result[key] = value;
}
return result;
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index cb22f29e54d..7cbc771c624 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -276,6 +276,11 @@ describe("parseOTLPHeaders", () => {
expect(parseOTLPHeaders("Authorization=Bearer%20tok%3Dvalue")).toEqual({ Authorization: "Bearer tok=value" });
});
+ it("decodes before trimming so encoded whitespace at edges is preserved", () => {
+ // %20 at start/end of value should survive: decode first, then trim removes nothing
+ expect(parseOTLPHeaders("X-Token=abc%20def")).toEqual({ "X-Token": "abc def" });
+ });
+
it("handles values containing = signs (only first = is delimiter)", () => {
expect(parseOTLPHeaders("Authorization=Bearer base64==")).toEqual({ Authorization: "Bearer base64==" });
});
From 073a79efbb76b2b112bad0d35b14ebeb55856d7c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 14:26:06 +0000
Subject: [PATCH 11/16] feat: propagate trace/span IDs via GITHUB_ENV for
1-trace-per-run, 1-parent-span-per-job
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/95b6d36f-8ffa-4b60-8d50-426464993eec
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/index.js | 21 ++-
actions/setup/js/send_otlp_span.cjs | 72 ++++++++---
actions/setup/js/send_otlp_span.test.cjs | 155 ++++++++++++++++++++---
3 files changed, 205 insertions(+), 43 deletions(-)
diff --git a/actions/setup/index.js b/actions/setup/index.js
index e71b8f47aff..e9f2de948a8 100644
--- a/actions/setup/index.js
+++ b/actions/setup/index.js
@@ -39,14 +39,25 @@ if (result.status !== 0) {
(async () => {
try {
const { appendFileSync } = require("fs");
- const { isValidTraceId, sendJobSetupSpan } = require(path.join(__dirname, "js", "send_otlp_span.cjs"));
- const traceId = await sendJobSetupSpan({ startMs: setupStartMs });
- // Always expose the trace ID as an action output so downstream jobs can
- // reference it via `steps..outputs.trace-id` and pass it to their own
- // setup steps to correlate all job spans under a single trace.
+ const { isValidTraceId, isValidSpanId, sendJobSetupSpan } = require(path.join(__dirname, "js", "send_otlp_span.cjs"));
+ const { traceId, spanId } = await sendJobSetupSpan({ startMs: setupStartMs });
+ // Expose the trace ID as an action output so downstream jobs can reference it
+ // via `steps..outputs.trace-id` for cross-job trace correlation.
if (isValidTraceId(traceId) && process.env.GITHUB_OUTPUT) {
appendFileSync(process.env.GITHUB_OUTPUT, `trace-id=${traceId}\n`);
}
+ // Write both the trace ID and setup span ID to GITHUB_ENV so all subsequent
+ // steps in this job automatically inherit the parent trace context:
+ // GH_AW_TRACE_ID – shared trace ID (1 trace per run)
+ // GH_AW_PARENT_SPAN_ID – setup span ID used as parent (1 parent span per job)
+ if (process.env.GITHUB_ENV) {
+ if (isValidTraceId(traceId)) {
+ appendFileSync(process.env.GITHUB_ENV, `GH_AW_TRACE_ID=${traceId}\n`);
+ }
+ if (isValidSpanId(spanId)) {
+ appendFileSync(process.env.GITHUB_ENV, `GH_AW_PARENT_SPAN_ID=${spanId}\n`);
+ }
+ }
} catch {
// Non-fatal: silently ignore any OTLP export or output-write errors.
}
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
index bf3f0655bd1..56e3f90f543 100644
--- a/actions/setup/js/send_otlp_span.cjs
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -74,13 +74,14 @@ function buildAttr(key, value) {
/**
* @typedef {Object} OTLPSpanOptions
- * @property {string} traceId - 32-char hex trace ID
- * @property {string} spanId - 16-char hex span ID
- * @property {string} spanName - Human-readable span name
- * @property {number} startMs - Span start time (ms since epoch)
- * @property {number} endMs - Span end time (ms since epoch)
- * @property {string} serviceName - Value for the service.name resource attribute
- * @property {string} [scopeVersion] - gh-aw version string (e.g. from GH_AW_INFO_VERSION)
+ * @property {string} traceId - 32-char hex trace ID
+ * @property {string} spanId - 16-char hex span ID
+ * @property {string} [parentSpanId] - 16-char hex parent span ID; omitted for root spans
+ * @property {string} spanName - Human-readable span name
+ * @property {number} startMs - Span start time (ms since epoch)
+ * @property {number} endMs - Span end time (ms since epoch)
+ * @property {string} serviceName - Value for the service.name resource attribute
+ * @property {string} [scopeVersion] - gh-aw version string (e.g. from GH_AW_INFO_VERSION)
* @property {Array<{key: string, value: object}>} attributes - Span attributes
*/
@@ -90,7 +91,7 @@ function buildAttr(key, value) {
* @param {OTLPSpanOptions} opts
* @returns {object} - Ready to be serialised as JSON and POSTed to `/v1/traces`
*/
-function buildOTLPPayload({ traceId, spanId, spanName, startMs, endMs, serviceName, scopeVersion, attributes }) {
+function buildOTLPPayload({ traceId, spanId, parentSpanId, spanName, startMs, endMs, serviceName, scopeVersion, attributes }) {
return {
resourceSpans: [
{
@@ -104,6 +105,7 @@ function buildOTLPPayload({ traceId, spanId, spanName, startMs, endMs, serviceNa
{
traceId,
spanId,
+ ...(parentSpanId ? { parentSpanId } : {}),
name: spanName,
kind: 2, // SPAN_KIND_SERVER
startTimeUnixNano: toNanoString(startMs),
@@ -219,6 +221,21 @@ function isValidTraceId(id) {
return TRACE_ID_RE.test(id);
}
+/**
+ * Regular expression that matches a valid OTLP span ID: 16 lowercase hex characters.
+ * @type {RegExp}
+ */
+const SPAN_ID_RE = /^[0-9a-f]{16}$/;
+
+/**
+ * Validate that a string is a well-formed OTLP span ID (16 lowercase hex chars).
+ * @param {string} id
+ * @returns {boolean}
+ */
+function isValidSpanId(id) {
+ return SPAN_ID_RE.test(id);
+}
+
/**
* @typedef {Object} SendJobSetupSpanOptions
* @property {number} [startMs] - Override for the span start time (ms). Defaults to `Date.now()`.
@@ -233,9 +250,10 @@ function isValidTraceId(id) {
* Send a `gh-aw.job.setup` span to the configured OTLP endpoint.
*
* This is designed to be called from `actions/setup/index.js` immediately after
- * the setup script completes. It always returns the trace ID so callers can
- * expose it as an action output for cross-job correlation — even when
- * `OTEL_EXPORTER_OTLP_ENDPOINT` is not set (no span is sent in that case).
+ * the setup script completes. It always returns `{ traceId, spanId }` so callers
+ * can expose the trace ID as an action output and write both values to `$GITHUB_ENV`
+ * for downstream step correlation — even when `OTEL_EXPORTER_OTLP_ENDPOINT` is not
+ * set (no span is sent in that case).
* Errors are swallowed so the workflow is never broken by tracing failures.
*
* Environment variables consumed:
@@ -250,7 +268,7 @@ function isValidTraceId(id) {
* - `GITHUB_REPOSITORY` – `owner/repo` string
*
* @param {SendJobSetupSpanOptions} [options]
- * @returns {Promise} The trace ID used for the span (generated or passed in).
+ * @returns {Promise<{ traceId: string, spanId: string }>} The trace and span IDs used.
*/
async function sendJobSetupSpan(options = {}) {
// Resolve the trace ID before the early-return so it is always available as
@@ -268,9 +286,14 @@ async function sendJobSetupSpan(options = {}) {
const traceId = optionsTraceId || inputTraceId || generateTraceId();
+ // Always generate a span ID so it can be written to GITHUB_ENV as
+ // GH_AW_PARENT_SPAN_ID even when OTLP is not configured, allowing downstream
+ // scripts to establish the correct parent span context.
+ const spanId = generateSpanId();
+
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "";
if (!endpoint) {
- return traceId;
+ return { traceId, spanId };
}
const startMs = options.startMs ?? Date.now();
@@ -292,7 +315,7 @@ async function sendJobSetupSpan(options = {}) {
const payload = buildOTLPPayload({
traceId,
- spanId: generateSpanId(),
+ spanId,
spanName: "gh-aw.job.setup",
startMs,
endMs,
@@ -302,7 +325,7 @@ async function sendJobSetupSpan(options = {}) {
});
await sendOTLPSpan(endpoint, payload);
- return traceId;
+ return { traceId, spanId };
}
// ---------------------------------------------------------------------------
@@ -340,6 +363,10 @@ function readJSONIfExists(filePath) {
* - `OTEL_EXPORTER_OTLP_ENDPOINT` – collector endpoint
* - `OTEL_SERVICE_NAME` – service name (defaults to "gh-aw")
* - `GH_AW_EFFECTIVE_TOKENS` – total effective token count for the run
+ * - `GH_AW_TRACE_ID` – trace ID written to GITHUB_ENV by the setup step;
+ * enables 1-trace-per-run when present
+ * - `GH_AW_PARENT_SPAN_ID` – setup span ID written to GITHUB_ENV by the setup step;
+ * links this span as a child of the job setup span
* - `GITHUB_RUN_ID` – GitHub Actions run ID
* - `GITHUB_ACTOR` – GitHub Actions actor
* - `GITHUB_REPOSITORY` – `owner/repo` string
@@ -370,10 +397,17 @@ async function sendJobConclusionSpan(spanName, options = {}) {
const serviceName = process.env.OTEL_SERVICE_NAME || "gh-aw";
const version = awInfo.agent_version || awInfo.version || process.env.GH_AW_INFO_VERSION || "unknown";
- // Use the workflow_call_id from aw_info as the trace ID when available so that
- // conclusion spans can be correlated with the activation span.
+ // Prefer GH_AW_TRACE_ID (written to GITHUB_ENV by this job's setup step) so
+ // all spans in the same job share one trace. Fall back to the workflow_call_id
+ // from aw_info for cross-job correlation, then generate a fresh ID.
+ const envTraceId = (process.env.GH_AW_TRACE_ID || "").trim().toLowerCase();
const awTraceId = typeof awInfo.context?.workflow_call_id === "string" ? awInfo.context.workflow_call_id.replace(/-/g, "") : "";
- const traceId = awTraceId && isValidTraceId(awTraceId) ? awTraceId : generateTraceId();
+ const traceId = (isValidTraceId(envTraceId) ? envTraceId : null) || (awTraceId && isValidTraceId(awTraceId) ? awTraceId : null) || generateTraceId();
+
+ // Use GH_AW_PARENT_SPAN_ID (written to GITHUB_ENV by this job's setup step) so
+ // conclusion spans are linked as children of the setup span (1 parent span per job).
+ const rawParentSpanId = (process.env.GH_AW_PARENT_SPAN_ID || "").trim().toLowerCase();
+ const parentSpanId = isValidSpanId(rawParentSpanId) ? rawParentSpanId : "";
const workflowName = awInfo.workflow_name || "";
const engineId = awInfo.engine_id || "";
@@ -393,6 +427,7 @@ async function sendJobConclusionSpan(spanName, options = {}) {
const payload = buildOTLPPayload({
traceId,
spanId: generateSpanId(),
+ ...(parentSpanId ? { parentSpanId } : {}),
spanName,
startMs,
endMs: Date.now(),
@@ -406,6 +441,7 @@ async function sendJobConclusionSpan(spanName, options = {}) {
module.exports = {
isValidTraceId,
+ isValidSpanId,
generateTraceId,
generateSpanId,
toNanoString,
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index 7cbc771c624..d82ee213f87 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -4,7 +4,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
// Module import
// ---------------------------------------------------------------------------
-const { isValidTraceId, generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, parseOTLPHeaders, sendOTLPSpan, sendJobSetupSpan, sendJobConclusionSpan } = await import("./send_otlp_span.cjs");
+const { isValidTraceId, isValidSpanId, generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, parseOTLPHeaders, sendOTLPSpan, sendJobSetupSpan, sendJobConclusionSpan } = await import("./send_otlp_span.cjs");
// ---------------------------------------------------------------------------
// isValidTraceId
@@ -34,6 +34,34 @@ describe("isValidTraceId", () => {
});
});
+// ---------------------------------------------------------------------------
+// isValidSpanId
+// ---------------------------------------------------------------------------
+
+describe("isValidSpanId", () => {
+ it("accepts a valid 16-character lowercase hex span ID", () => {
+ expect(isValidSpanId("b".repeat(16))).toBe(true);
+ expect(isValidSpanId("0123456789abcdef")).toBe(true);
+ });
+
+ it("rejects uppercase hex characters", () => {
+ expect(isValidSpanId("B".repeat(16))).toBe(false);
+ });
+
+ it("rejects strings that are too short or too long", () => {
+ expect(isValidSpanId("b".repeat(15))).toBe(false);
+ expect(isValidSpanId("b".repeat(17))).toBe(false);
+ });
+
+ it("rejects empty string", () => {
+ expect(isValidSpanId("")).toBe(false);
+ });
+
+ it("rejects non-hex characters", () => {
+ expect(isValidSpanId("z".repeat(16))).toBe(false);
+ });
+});
+
// ---------------------------------------------------------------------------
// generateTraceId
// ---------------------------------------------------------------------------
@@ -167,6 +195,35 @@ describe("buildOTLPPayload", () => {
});
expect(payload.resourceSpans[0].scopeSpans[0].scope.version).toBe("unknown");
});
+
+ it("includes parentSpanId in span when provided", () => {
+ const payload = buildOTLPPayload({
+ traceId: "a".repeat(32),
+ spanId: "b".repeat(16),
+ parentSpanId: "c".repeat(16),
+ spanName: "test",
+ startMs: 0,
+ endMs: 1,
+ serviceName: "gh-aw",
+ attributes: [],
+ });
+ const span = payload.resourceSpans[0].scopeSpans[0].spans[0];
+ expect(span.parentSpanId).toBe("c".repeat(16));
+ });
+
+ it("omits parentSpanId from span when not provided", () => {
+ const payload = buildOTLPPayload({
+ traceId: "a".repeat(32),
+ spanId: "b".repeat(16),
+ spanName: "test",
+ startMs: 0,
+ endMs: 1,
+ serviceName: "gh-aw",
+ attributes: [],
+ });
+ const span = payload.resourceSpans[0].scopeSpans[0].spans[0];
+ expect(span.parentSpanId).toBeUndefined();
+ });
});
// ---------------------------------------------------------------------------
@@ -383,22 +440,23 @@ describe("sendJobSetupSpan", () => {
return undefined;
}
- it("returns a trace ID even when OTEL_EXPORTER_OTLP_ENDPOINT is not set", async () => {
- const traceId = await sendJobSetupSpan();
+ it("returns a trace ID and span ID even when OTEL_EXPORTER_OTLP_ENDPOINT is not set", async () => {
+ const { traceId, spanId } = await sendJobSetupSpan();
expect(traceId).toMatch(/^[0-9a-f]{32}$/);
+ expect(spanId).toMatch(/^[0-9a-f]{16}$/);
expect(fetch).not.toHaveBeenCalled();
});
it("returns the same trace ID when called with INPUT_TRACE_ID and no endpoint", async () => {
process.env.INPUT_TRACE_ID = "a".repeat(32);
- const traceId = await sendJobSetupSpan();
+ const { traceId } = await sendJobSetupSpan();
expect(traceId).toBe("a".repeat(32));
expect(fetch).not.toHaveBeenCalled();
});
it("generates a new trace ID when INPUT_TRACE_ID is invalid", async () => {
process.env.INPUT_TRACE_ID = "not-a-valid-trace-id";
- const traceId = await sendJobSetupSpan();
+ const { traceId } = await sendJobSetupSpan();
expect(traceId).toMatch(/^[0-9a-f]{32}$/);
expect(traceId).not.toBe("not-a-valid-trace-id");
});
@@ -406,17 +464,17 @@ describe("sendJobSetupSpan", () => {
it("normalises uppercase INPUT_TRACE_ID to lowercase and accepts it", async () => {
// Trace IDs pasted from external tools may be uppercase; we normalise them.
process.env.INPUT_TRACE_ID = "A".repeat(32);
- const traceId = await sendJobSetupSpan();
+ const { traceId } = await sendJobSetupSpan();
expect(traceId).toBe("a".repeat(32));
});
it("rejects an invalid options.traceId and generates a new trace ID", async () => {
- const returned = await sendJobSetupSpan({ traceId: "too-short" });
- expect(returned).toMatch(/^[0-9a-f]{32}$/);
- expect(returned).not.toBe("too-short");
+ const { traceId } = await sendJobSetupSpan({ traceId: "too-short" });
+ expect(traceId).toMatch(/^[0-9a-f]{32}$/);
+ expect(traceId).not.toBe("too-short");
});
- it("sends a span when endpoint is configured and returns the trace ID", async () => {
+ it("sends a span when endpoint is configured and returns the trace ID and span ID", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
vi.stubGlobal("fetch", mockFetch);
@@ -428,9 +486,10 @@ describe("sendJobSetupSpan", () => {
process.env.GITHUB_ACTOR = "octocat";
process.env.GITHUB_REPOSITORY = "owner/repo";
- const traceId = await sendJobSetupSpan();
+ const { traceId, spanId } = await sendJobSetupSpan();
expect(traceId).toMatch(/^[0-9a-f]{32}$/);
+ expect(spanId).toMatch(/^[0-9a-f]{16}$/);
expect(mockFetch).toHaveBeenCalledOnce();
const [url, init] = mockFetch.mock.calls[0];
expect(url).toBe("https://traces.example.com/v1/traces");
@@ -439,9 +498,9 @@ describe("sendJobSetupSpan", () => {
const body = JSON.parse(init.body);
const span = body.resourceSpans[0].scopeSpans[0].spans[0];
expect(span.name).toBe("gh-aw.job.setup");
- // Span traceId must match the returned value (cross-job correlation)
+ // Span traceId and spanId must match the returned values
expect(span.traceId).toBe(traceId);
- expect(span.spanId).toMatch(/^[0-9a-f]{16}$/);
+ expect(span.spanId).toBe(spanId);
const attrs = Object.fromEntries(span.attributes.map(a => [a.key, attrValue(a)]));
expect(attrs["gh-aw.job.name"]).toBe("agent");
@@ -459,9 +518,9 @@ describe("sendJobSetupSpan", () => {
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
const correlationTraceId = "b".repeat(32);
- const returned = await sendJobSetupSpan({ traceId: correlationTraceId });
+ const { traceId } = await sendJobSetupSpan({ traceId: correlationTraceId });
- expect(returned).toBe(correlationTraceId);
+ expect(traceId).toBe(correlationTraceId);
const body = JSON.parse(mockFetch.mock.calls[0][1].body);
expect(body.resourceSpans[0].scopeSpans[0].spans[0].traceId).toBe(correlationTraceId);
});
@@ -473,9 +532,9 @@ describe("sendJobSetupSpan", () => {
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
process.env.INPUT_TRACE_ID = "c".repeat(32);
- const returned = await sendJobSetupSpan();
+ const { traceId } = await sendJobSetupSpan();
- expect(returned).toBe("c".repeat(32));
+ expect(traceId).toBe("c".repeat(32));
const body = JSON.parse(mockFetch.mock.calls[0][1].body);
expect(body.resourceSpans[0].scopeSpans[0].spans[0].traceId).toBe("c".repeat(32));
});
@@ -487,9 +546,9 @@ describe("sendJobSetupSpan", () => {
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
process.env.INPUT_TRACE_ID = "d".repeat(32);
- const returned = await sendJobSetupSpan({ traceId: "e".repeat(32) });
+ const { traceId } = await sendJobSetupSpan({ traceId: "e".repeat(32) });
- expect(returned).toBe("e".repeat(32));
+ expect(traceId).toBe("e".repeat(32));
const body = JSON.parse(mockFetch.mock.calls[0][1].body);
expect(body.resourceSpans[0].scopeSpans[0].spans[0].traceId).toBe("e".repeat(32));
});
@@ -543,7 +602,7 @@ describe("sendJobSetupSpan", () => {
describe("sendJobConclusionSpan", () => {
/** @type {Record} */
const savedEnv = {};
- const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "GH_AW_EFFECTIVE_TOKENS", "GH_AW_INFO_VERSION", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
+ const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "GH_AW_EFFECTIVE_TOKENS", "GH_AW_INFO_VERSION", "GH_AW_TRACE_ID", "GH_AW_PARENT_SPAN_ID", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
beforeEach(() => {
vi.stubGlobal("fetch", vi.fn());
@@ -630,4 +689,60 @@ describe("sendJobConclusionSpan", () => {
const body = JSON.parse(mockFetch.mock.calls[0][1].body);
expect(body.resourceSpans[0].scopeSpans[0].scope.version).toBe("v2.0.0");
});
+
+ it("uses GH_AW_TRACE_ID from env as trace ID (1 trace per run)", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ process.env.GH_AW_TRACE_ID = "f".repeat(32);
+
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
+
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ const span = body.resourceSpans[0].scopeSpans[0].spans[0];
+ expect(span.traceId).toBe("f".repeat(32));
+ });
+
+ it("uses GH_AW_PARENT_SPAN_ID as parentSpanId (1 parent span per job)", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ const parentSpanId = "abcdef1234567890";
+ process.env.GH_AW_PARENT_SPAN_ID = parentSpanId;
+
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
+
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ const span = body.resourceSpans[0].scopeSpans[0].spans[0];
+ expect(span.parentSpanId).toBe(parentSpanId);
+ });
+
+ it("omits parentSpanId when GH_AW_PARENT_SPAN_ID is absent", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
+
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ const span = body.resourceSpans[0].scopeSpans[0].spans[0];
+ expect(span.parentSpanId).toBeUndefined();
+ });
+
+ it("normalises uppercase GH_AW_TRACE_ID to lowercase", async () => {
+ const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
+ vi.stubGlobal("fetch", mockFetch);
+
+ process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
+ process.env.GH_AW_TRACE_ID = "F".repeat(32); // uppercase — should be normalised
+
+ await sendJobConclusionSpan("gh-aw.job.conclusion");
+
+ const body = JSON.parse(mockFetch.mock.calls[0][1].body);
+ const span = body.resourceSpans[0].scopeSpans[0].spans[0];
+ expect(span.traceId).toBe("f".repeat(32));
+ });
});
From 4f094e4e5476d49831224d319fb0582f25a9ccfb Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 14:30:12 +0000
Subject: [PATCH 12/16] fix: simplify traceId resolution logic, normalize
spelling to American English
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/95b6d36f-8ffa-4b60-8d50-426464993eec
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/js/send_otlp_span.cjs | 9 +++++++--
actions/setup/js/send_otlp_span.test.cjs | 4 ++--
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
index 56e3f90f543..af5b195b87a 100644
--- a/actions/setup/js/send_otlp_span.cjs
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -279,7 +279,7 @@ async function sendJobSetupSpan(options = {}) {
// Validate options.traceId if supplied; callers may pass raw user input.
const optionsTraceId = options.traceId && isValidTraceId(options.traceId) ? options.traceId : "";
- // Normalise INPUT_TRACE_ID to lowercase before validating: OTLP requires lowercase
+ // Normalize INPUT_TRACE_ID to lowercase before validating: OTLP requires lowercase
// hex, but trace IDs pasted from external tools may use uppercase characters.
const rawInputTraceId = (process.env.INPUT_TRACE_ID || "").trim().toLowerCase();
const inputTraceId = isValidTraceId(rawInputTraceId) ? rawInputTraceId : "";
@@ -402,7 +402,12 @@ async function sendJobConclusionSpan(spanName, options = {}) {
// from aw_info for cross-job correlation, then generate a fresh ID.
const envTraceId = (process.env.GH_AW_TRACE_ID || "").trim().toLowerCase();
const awTraceId = typeof awInfo.context?.workflow_call_id === "string" ? awInfo.context.workflow_call_id.replace(/-/g, "") : "";
- const traceId = (isValidTraceId(envTraceId) ? envTraceId : null) || (awTraceId && isValidTraceId(awTraceId) ? awTraceId : null) || generateTraceId();
+ let traceId = generateTraceId();
+ if (isValidTraceId(envTraceId)) {
+ traceId = envTraceId;
+ } else if (awTraceId && isValidTraceId(awTraceId)) {
+ traceId = awTraceId;
+ }
// Use GH_AW_PARENT_SPAN_ID (written to GITHUB_ENV by this job's setup step) so
// conclusion spans are linked as children of the setup span (1 parent span per job).
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index d82ee213f87..6d9b944246e 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -461,7 +461,7 @@ describe("sendJobSetupSpan", () => {
expect(traceId).not.toBe("not-a-valid-trace-id");
});
- it("normalises uppercase INPUT_TRACE_ID to lowercase and accepts it", async () => {
+ it("normalizes uppercase INPUT_TRACE_ID to lowercase and accepts it", async () => {
// Trace IDs pasted from external tools may be uppercase; we normalise them.
process.env.INPUT_TRACE_ID = "A".repeat(32);
const { traceId } = await sendJobSetupSpan();
@@ -732,7 +732,7 @@ describe("sendJobConclusionSpan", () => {
expect(span.parentSpanId).toBeUndefined();
});
- it("normalises uppercase GH_AW_TRACE_ID to lowercase", async () => {
+ it("normalizes uppercase GH_AW_TRACE_ID to lowercase", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
vi.stubGlobal("fetch", mockFetch);
From e3ae9139f8175f8d6901e84813f32e4b2969f339 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 14:43:40 +0000
Subject: [PATCH 13/16] refactor: rename GH_AW_TRACE_ID/GH_AW_PARENT_SPAN_ID to
GITHUB_AW_OTEL_ prefix
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/9fa99f5e-6d91-46ad-8cf4-797227c2651c
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/index.js | 8 ++++----
actions/setup/js/send_otlp_span.cjs | 14 +++++++-------
actions/setup/js/send_otlp_span.test.cjs | 16 ++++++++--------
3 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/actions/setup/index.js b/actions/setup/index.js
index e9f2de948a8..a0f377a28a9 100644
--- a/actions/setup/index.js
+++ b/actions/setup/index.js
@@ -48,14 +48,14 @@ if (result.status !== 0) {
}
// Write both the trace ID and setup span ID to GITHUB_ENV so all subsequent
// steps in this job automatically inherit the parent trace context:
- // GH_AW_TRACE_ID – shared trace ID (1 trace per run)
- // GH_AW_PARENT_SPAN_ID – setup span ID used as parent (1 parent span per job)
+ // GITHUB_AW_OTEL_TRACE_ID – shared trace ID (1 trace per run)
+ // GITHUB_AW_OTEL_PARENT_SPAN_ID – setup span ID used as parent (1 parent span per job)
if (process.env.GITHUB_ENV) {
if (isValidTraceId(traceId)) {
- appendFileSync(process.env.GITHUB_ENV, `GH_AW_TRACE_ID=${traceId}\n`);
+ appendFileSync(process.env.GITHUB_ENV, `GITHUB_AW_OTEL_TRACE_ID=${traceId}\n`);
}
if (isValidSpanId(spanId)) {
- appendFileSync(process.env.GITHUB_ENV, `GH_AW_PARENT_SPAN_ID=${spanId}\n`);
+ appendFileSync(process.env.GITHUB_ENV, `GITHUB_AW_OTEL_PARENT_SPAN_ID=${spanId}\n`);
}
}
} catch {
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
index af5b195b87a..d5f9905d976 100644
--- a/actions/setup/js/send_otlp_span.cjs
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -287,7 +287,7 @@ async function sendJobSetupSpan(options = {}) {
const traceId = optionsTraceId || inputTraceId || generateTraceId();
// Always generate a span ID so it can be written to GITHUB_ENV as
- // GH_AW_PARENT_SPAN_ID even when OTLP is not configured, allowing downstream
+ // GITHUB_AW_OTEL_PARENT_SPAN_ID even when OTLP is not configured, allowing downstream
// scripts to establish the correct parent span context.
const spanId = generateSpanId();
@@ -363,9 +363,9 @@ function readJSONIfExists(filePath) {
* - `OTEL_EXPORTER_OTLP_ENDPOINT` – collector endpoint
* - `OTEL_SERVICE_NAME` – service name (defaults to "gh-aw")
* - `GH_AW_EFFECTIVE_TOKENS` – total effective token count for the run
- * - `GH_AW_TRACE_ID` – trace ID written to GITHUB_ENV by the setup step;
+ * - `GITHUB_AW_OTEL_TRACE_ID` – trace ID written to GITHUB_ENV by the setup step;
* enables 1-trace-per-run when present
- * - `GH_AW_PARENT_SPAN_ID` – setup span ID written to GITHUB_ENV by the setup step;
+ * - `GITHUB_AW_OTEL_PARENT_SPAN_ID` – setup span ID written to GITHUB_ENV by the setup step;
* links this span as a child of the job setup span
* - `GITHUB_RUN_ID` – GitHub Actions run ID
* - `GITHUB_ACTOR` – GitHub Actions actor
@@ -397,10 +397,10 @@ async function sendJobConclusionSpan(spanName, options = {}) {
const serviceName = process.env.OTEL_SERVICE_NAME || "gh-aw";
const version = awInfo.agent_version || awInfo.version || process.env.GH_AW_INFO_VERSION || "unknown";
- // Prefer GH_AW_TRACE_ID (written to GITHUB_ENV by this job's setup step) so
+ // Prefer GITHUB_AW_OTEL_TRACE_ID (written to GITHUB_ENV by this job's setup step) so
// all spans in the same job share one trace. Fall back to the workflow_call_id
// from aw_info for cross-job correlation, then generate a fresh ID.
- const envTraceId = (process.env.GH_AW_TRACE_ID || "").trim().toLowerCase();
+ const envTraceId = (process.env.GITHUB_AW_OTEL_TRACE_ID || "").trim().toLowerCase();
const awTraceId = typeof awInfo.context?.workflow_call_id === "string" ? awInfo.context.workflow_call_id.replace(/-/g, "") : "";
let traceId = generateTraceId();
if (isValidTraceId(envTraceId)) {
@@ -409,9 +409,9 @@ async function sendJobConclusionSpan(spanName, options = {}) {
traceId = awTraceId;
}
- // Use GH_AW_PARENT_SPAN_ID (written to GITHUB_ENV by this job's setup step) so
+ // Use GITHUB_AW_OTEL_PARENT_SPAN_ID (written to GITHUB_ENV by this job's setup step) so
// conclusion spans are linked as children of the setup span (1 parent span per job).
- const rawParentSpanId = (process.env.GH_AW_PARENT_SPAN_ID || "").trim().toLowerCase();
+ const rawParentSpanId = (process.env.GITHUB_AW_OTEL_PARENT_SPAN_ID || "").trim().toLowerCase();
const parentSpanId = isValidSpanId(rawParentSpanId) ? rawParentSpanId : "";
const workflowName = awInfo.workflow_name || "";
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index 6d9b944246e..d0957047419 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -602,7 +602,7 @@ describe("sendJobSetupSpan", () => {
describe("sendJobConclusionSpan", () => {
/** @type {Record} */
const savedEnv = {};
- const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "GH_AW_EFFECTIVE_TOKENS", "GH_AW_INFO_VERSION", "GH_AW_TRACE_ID", "GH_AW_PARENT_SPAN_ID", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
+ const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "GH_AW_EFFECTIVE_TOKENS", "GH_AW_INFO_VERSION", "GITHUB_AW_OTEL_TRACE_ID", "GITHUB_AW_OTEL_PARENT_SPAN_ID", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
beforeEach(() => {
vi.stubGlobal("fetch", vi.fn());
@@ -690,12 +690,12 @@ describe("sendJobConclusionSpan", () => {
expect(body.resourceSpans[0].scopeSpans[0].scope.version).toBe("v2.0.0");
});
- it("uses GH_AW_TRACE_ID from env as trace ID (1 trace per run)", async () => {
+ it("uses GITHUB_AW_OTEL_TRACE_ID from env as trace ID (1 trace per run)", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
vi.stubGlobal("fetch", mockFetch);
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
- process.env.GH_AW_TRACE_ID = "f".repeat(32);
+ process.env.GITHUB_AW_OTEL_TRACE_ID = "f".repeat(32);
await sendJobConclusionSpan("gh-aw.job.conclusion");
@@ -704,13 +704,13 @@ describe("sendJobConclusionSpan", () => {
expect(span.traceId).toBe("f".repeat(32));
});
- it("uses GH_AW_PARENT_SPAN_ID as parentSpanId (1 parent span per job)", async () => {
+ it("uses GITHUB_AW_OTEL_PARENT_SPAN_ID as parentSpanId (1 parent span per job)", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
vi.stubGlobal("fetch", mockFetch);
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
const parentSpanId = "abcdef1234567890";
- process.env.GH_AW_PARENT_SPAN_ID = parentSpanId;
+ process.env.GITHUB_AW_OTEL_PARENT_SPAN_ID = parentSpanId;
await sendJobConclusionSpan("gh-aw.job.conclusion");
@@ -719,7 +719,7 @@ describe("sendJobConclusionSpan", () => {
expect(span.parentSpanId).toBe(parentSpanId);
});
- it("omits parentSpanId when GH_AW_PARENT_SPAN_ID is absent", async () => {
+ it("omits parentSpanId when GITHUB_AW_OTEL_PARENT_SPAN_ID is absent", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
vi.stubGlobal("fetch", mockFetch);
@@ -732,12 +732,12 @@ describe("sendJobConclusionSpan", () => {
expect(span.parentSpanId).toBeUndefined();
});
- it("normalizes uppercase GH_AW_TRACE_ID to lowercase", async () => {
+ it("normalizes uppercase GITHUB_AW_OTEL_TRACE_ID to lowercase", async () => {
const mockFetch = vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" });
vi.stubGlobal("fetch", mockFetch);
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com";
- process.env.GH_AW_TRACE_ID = "F".repeat(32); // uppercase — should be normalised
+ process.env.GITHUB_AW_OTEL_TRACE_ID = "F".repeat(32); // uppercase — should be normalised
await sendJobConclusionSpan("gh-aw.job.conclusion");
From a361f5c16ac46b56cdbfcf2bdd76b09cdee714d4 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 14:53:53 +0000
Subject: [PATCH 14/16] feat: mirror every OTLP span to /tmp/gh-aw/otel.jsonl
for artifact inspection
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/c17643f9-a18d-46b3-a0e5-5c43dc2d1298
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
actions/setup/js/constants.cjs | 8 ++
actions/setup/js/send_otlp_span.cjs | 34 +++++++
actions/setup/js/send_otlp_span.test.cjs | 110 ++++++++++++++++++++++-
3 files changed, 151 insertions(+), 1 deletion(-)
diff --git a/actions/setup/js/constants.cjs b/actions/setup/js/constants.cjs
index 6adcb33b0d4..5fa4be27b2d 100644
--- a/actions/setup/js/constants.cjs
+++ b/actions/setup/js/constants.cjs
@@ -80,6 +80,13 @@ const RPC_MESSAGES_PATH = `${TMP_GH_AW_PATH}/mcp-logs/rpc-messages.jsonl`;
*/
const MANIFEST_FILE_PATH = `${TMP_GH_AW_PATH}/safe-output-items.jsonl`;
+/**
+ * Path to the OTLP telemetry mirror file.
+ * Every OTLP span payload is appended here as a JSON line for artifact inspection.
+ * @type {string}
+ */
+const OTEL_JSONL_PATH = `${TMP_GH_AW_PATH}/otel.jsonl`;
+
/**
* Filename of the threat detection log written by the detection engine via tee.
* The detection copilot's stdout (containing THREAT_DETECTION_RESULT) is piped
@@ -98,5 +105,6 @@ module.exports = {
GATEWAY_JSONL_PATH,
RPC_MESSAGES_PATH,
MANIFEST_FILE_PATH,
+ OTEL_JSONL_PATH,
DETECTION_LOG_FILENAME,
};
diff --git a/actions/setup/js/send_otlp_span.cjs b/actions/setup/js/send_otlp_span.cjs
index d5f9905d976..4b88a9e3540 100644
--- a/actions/setup/js/send_otlp_span.cjs
+++ b/actions/setup/js/send_otlp_span.cjs
@@ -121,6 +121,35 @@ function buildOTLPPayload({ traceId, spanId, parentSpanId, spanName, startMs, en
};
}
+// ---------------------------------------------------------------------------
+// Local JSONL mirror
+// ---------------------------------------------------------------------------
+
+/**
+ * Path to the OTLP telemetry mirror file.
+ * Every OTLP span payload is also appended here as a JSON line so that it can
+ * be inspected via GitHub Actions artifacts without needing a live collector.
+ * @type {string}
+ */
+const OTEL_JSONL_PATH = "/tmp/gh-aw/otel.jsonl";
+
+/**
+ * Append an OTLP payload as a single JSON line to the local telemetry mirror
+ * file. Creates the `/tmp/gh-aw` directory if it does not already exist.
+ * Errors are silently swallowed — mirror failures must never break the workflow.
+ *
+ * @param {object} payload - OTLP traces payload
+ * @returns {void}
+ */
+function appendToOTLPJSONL(payload) {
+ try {
+ fs.mkdirSync("/tmp/gh-aw", { recursive: true });
+ fs.appendFileSync(OTEL_JSONL_PATH, JSON.stringify(payload) + "\n");
+ } catch {
+ // Mirror failures are non-fatal; do not propagate.
+ }
+}
+
// ---------------------------------------------------------------------------
// HTTP transport
// ---------------------------------------------------------------------------
@@ -169,6 +198,9 @@ function parseOTLPHeaders(raw) {
* @returns {Promise}
*/
async function sendOTLPSpan(endpoint, payload, { maxRetries = 2, baseDelayMs = 100 } = {}) {
+ // Mirror payload locally so it survives even when the collector is unreachable.
+ appendToOTLPJSONL(payload);
+
const url = endpoint.replace(/\/$/, "") + "/v1/traces";
const extraHeaders = parseOTLPHeaders(process.env.OTEL_EXPORTER_OTLP_HEADERS || "");
const headers = { "Content-Type": "application/json", ...extraHeaders };
@@ -457,4 +489,6 @@ module.exports = {
readJSONIfExists,
sendJobSetupSpan,
sendJobConclusionSpan,
+ OTEL_JSONL_PATH,
+ appendToOTLPJSONL,
};
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index d0957047419..b0c58cbc4b3 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -1,10 +1,12 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+import fs from "fs";
// ---------------------------------------------------------------------------
// Module import
// ---------------------------------------------------------------------------
-const { isValidTraceId, isValidSpanId, generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, parseOTLPHeaders, sendOTLPSpan, sendJobSetupSpan, sendJobConclusionSpan } = await import("./send_otlp_span.cjs");
+const { isValidTraceId, isValidSpanId, generateTraceId, generateSpanId, toNanoString, buildAttr, buildOTLPPayload, parseOTLPHeaders, sendOTLPSpan, sendJobSetupSpan, sendJobConclusionSpan, OTEL_JSONL_PATH, appendToOTLPJSONL } =
+ await import("./send_otlp_span.cjs");
// ---------------------------------------------------------------------------
// isValidTraceId
@@ -231,12 +233,18 @@ describe("buildOTLPPayload", () => {
// ---------------------------------------------------------------------------
describe("sendOTLPSpan", () => {
+ let mkdirSpy, appendSpy;
+
beforeEach(() => {
vi.stubGlobal("fetch", vi.fn());
+ mkdirSpy = vi.spyOn(fs, "mkdirSync").mockImplementation(() => {});
+ appendSpy = vi.spyOn(fs, "appendFileSync").mockImplementation(() => {});
});
afterEach(() => {
vi.unstubAllGlobals();
+ mkdirSpy.mockRestore();
+ appendSpy.mockRestore();
});
it("POSTs JSON payload to endpoint/v1/traces", async () => {
@@ -308,6 +316,91 @@ describe("sendOTLPSpan", () => {
});
});
+// ---------------------------------------------------------------------------
+// appendToOTLPJSONL
+// ---------------------------------------------------------------------------
+
+describe("appendToOTLPJSONL", () => {
+ let mkdirSpy, appendSpy;
+
+ beforeEach(() => {
+ mkdirSpy = vi.spyOn(fs, "mkdirSync").mockImplementation(() => {});
+ appendSpy = vi.spyOn(fs, "appendFileSync").mockImplementation(() => {});
+ });
+
+ afterEach(() => {
+ mkdirSpy.mockRestore();
+ appendSpy.mockRestore();
+ });
+
+ it("writes payload as a JSON line to OTEL_JSONL_PATH", () => {
+ const payload = { resourceSpans: [{ spans: [] }] };
+ appendToOTLPJSONL(payload);
+
+ expect(appendSpy).toHaveBeenCalledOnce();
+ const [filePath, content] = appendSpy.mock.calls[0];
+ expect(filePath).toBe(OTEL_JSONL_PATH);
+ expect(content).toBe(JSON.stringify(payload) + "\n");
+ });
+
+ it("ensures /tmp/gh-aw directory exists before writing", () => {
+ appendToOTLPJSONL({});
+
+ expect(mkdirSpy).toHaveBeenCalledWith("/tmp/gh-aw", { recursive: true });
+ });
+
+ it("does not throw when appendFileSync fails", () => {
+ appendSpy.mockImplementation(() => {
+ throw new Error("disk full");
+ });
+
+ expect(() => appendToOTLPJSONL({ spans: [] })).not.toThrow();
+ });
+});
+
+// ---------------------------------------------------------------------------
+// sendOTLPSpan – JSONL mirror
+// ---------------------------------------------------------------------------
+
+describe("sendOTLPSpan JSONL mirror", () => {
+ let mkdirSpy, appendSpy;
+
+ beforeEach(() => {
+ mkdirSpy = vi.spyOn(fs, "mkdirSync").mockImplementation(() => {});
+ appendSpy = vi.spyOn(fs, "appendFileSync").mockImplementation(() => {});
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({ ok: true, status: 200, statusText: "OK" }));
+ });
+
+ afterEach(() => {
+ mkdirSpy.mockRestore();
+ appendSpy.mockRestore();
+ vi.unstubAllGlobals();
+ });
+
+ it("mirrors the payload to otel.jsonl even when fetch succeeds", async () => {
+ const payload = { resourceSpans: [] };
+ await sendOTLPSpan("https://traces.example.com", payload);
+
+ expect(appendSpy).toHaveBeenCalledOnce();
+ const [filePath, content] = appendSpy.mock.calls[0];
+ expect(filePath).toBe(OTEL_JSONL_PATH);
+ expect(content).toBe(JSON.stringify(payload) + "\n");
+ });
+
+ it("mirrors the payload to otel.jsonl even when fetch fails all retries", async () => {
+ vi.stubGlobal("fetch", vi.fn().mockResolvedValue({ ok: false, status: 503, statusText: "Unavailable" }));
+ const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
+
+ const payload = { resourceSpans: [{ note: "retry-test" }] };
+ await sendOTLPSpan("https://traces.example.com", payload, { maxRetries: 1, baseDelayMs: 1 });
+
+ expect(appendSpy).toHaveBeenCalledOnce();
+ expect(appendSpy.mock.calls[0][1]).toBe(JSON.stringify(payload) + "\n");
+
+ warnSpy.mockRestore();
+ });
+});
+
// ---------------------------------------------------------------------------
// parseOTLPHeaders
// ---------------------------------------------------------------------------
@@ -359,14 +452,19 @@ describe("parseOTLPHeaders", () => {
describe("sendOTLPSpan with OTEL_EXPORTER_OTLP_HEADERS", () => {
const savedHeaders = process.env.OTEL_EXPORTER_OTLP_HEADERS;
+ let mkdirSpy, appendSpy;
beforeEach(() => {
vi.stubGlobal("fetch", vi.fn());
delete process.env.OTEL_EXPORTER_OTLP_HEADERS;
+ mkdirSpy = vi.spyOn(fs, "mkdirSync").mockImplementation(() => {});
+ appendSpy = vi.spyOn(fs, "appendFileSync").mockImplementation(() => {});
});
afterEach(() => {
vi.unstubAllGlobals();
+ mkdirSpy.mockRestore();
+ appendSpy.mockRestore();
if (savedHeaders !== undefined) {
process.env.OTEL_EXPORTER_OTLP_HEADERS = savedHeaders;
} else {
@@ -406,6 +504,7 @@ describe("sendJobSetupSpan", () => {
/** @type {Record} */
const savedEnv = {};
const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "INPUT_JOB_NAME", "INPUT_TRACE_ID", "GH_AW_INFO_WORKFLOW_NAME", "GH_AW_INFO_ENGINE_ID", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
+ let mkdirSpy, appendSpy;
beforeEach(() => {
vi.stubGlobal("fetch", vi.fn());
@@ -413,6 +512,8 @@ describe("sendJobSetupSpan", () => {
savedEnv[k] = process.env[k];
delete process.env[k];
}
+ mkdirSpy = vi.spyOn(fs, "mkdirSync").mockImplementation(() => {});
+ appendSpy = vi.spyOn(fs, "appendFileSync").mockImplementation(() => {});
});
afterEach(() => {
@@ -424,6 +525,8 @@ describe("sendJobSetupSpan", () => {
delete process.env[k];
}
}
+ mkdirSpy.mockRestore();
+ appendSpy.mockRestore();
});
/**
@@ -603,6 +706,7 @@ describe("sendJobConclusionSpan", () => {
/** @type {Record} */
const savedEnv = {};
const envKeys = ["OTEL_EXPORTER_OTLP_ENDPOINT", "OTEL_SERVICE_NAME", "GH_AW_EFFECTIVE_TOKENS", "GH_AW_INFO_VERSION", "GITHUB_AW_OTEL_TRACE_ID", "GITHUB_AW_OTEL_PARENT_SPAN_ID", "GITHUB_RUN_ID", "GITHUB_ACTOR", "GITHUB_REPOSITORY"];
+ let mkdirSpy, appendSpy;
beforeEach(() => {
vi.stubGlobal("fetch", vi.fn());
@@ -610,6 +714,8 @@ describe("sendJobConclusionSpan", () => {
savedEnv[k] = process.env[k];
delete process.env[k];
}
+ mkdirSpy = vi.spyOn(fs, "mkdirSync").mockImplementation(() => {});
+ appendSpy = vi.spyOn(fs, "appendFileSync").mockImplementation(() => {});
});
afterEach(() => {
@@ -621,6 +727,8 @@ describe("sendJobConclusionSpan", () => {
delete process.env[k];
}
}
+ mkdirSpy.mockRestore();
+ appendSpy.mockRestore();
});
it("is a no-op when OTEL_EXPORTER_OTLP_ENDPOINT is not set", async () => {
From 1c1b54f8317c02676053d0efe154b9fc7bb29db3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 15:14:08 +0000
Subject: [PATCH 15/16] feat: configure smoke-copilot with OTLP secrets; fix
raw frontmatter OTLP injection
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/21afe94c-2d9a-4d15-9dab-6859ad6cc23b
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
.github/workflows/smoke-copilot-arm.lock.yml | 59 ++++-----
.github/workflows/smoke-copilot-arm.md | 4 +
.github/workflows/smoke-copilot.lock.yml | 59 ++++-----
.github/workflows/smoke-copilot.md | 4 +
actions/setup/js/send_otlp_span.test.cjs | 15 +++
pkg/workflow/frontmatter_types.go | 6 +-
pkg/workflow/observability_otlp.go | 49 +++++++-
pkg/workflow/observability_otlp_test.go | 120 +++++++++++++++++++
8 files changed, 257 insertions(+), 59 deletions(-)
diff --git a/.github/workflows/smoke-copilot-arm.lock.yml b/.github/workflows/smoke-copilot-arm.lock.yml
index e91eddbc1bc..74795062670 100644
--- a/.github/workflows/smoke-copilot-arm.lock.yml
+++ b/.github/workflows/smoke-copilot-arm.lock.yml
@@ -30,7 +30,7 @@
# - shared/mcp/serena.md
# - shared/reporting.md
#
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"3e2fe69aad7d2801364a57386fae783d35b5afda5c4e976f829c5953a22349a5","agent_id":"copilot"}
+# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"e603d70b7bc3dba0312876331b6f358c10fbf40a13be449d18d2a71c98cc8c70","agent_id":"copilot"}
name: "Smoke Copilot ARM64"
"on":
@@ -55,6 +55,11 @@ concurrency:
run-name: "Smoke Copilot ARM64"
+env:
+ OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.GH_AW_OTEL_ENDPOINT }}
+ OTEL_SERVICE_NAME: gh-aw
+ OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.GH_AW_OTEL_HEADERS }}
+
jobs:
activation:
needs: pre_activation
@@ -192,9 +197,9 @@ jobs:
run: |
bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh
{
- cat << 'GH_AW_PROMPT_5d913d5c763dcde8_EOF'
+ cat << 'GH_AW_PROMPT_e1fc2cb2cbeaacc4_EOF'
- GH_AW_PROMPT_5d913d5c763dcde8_EOF
+ GH_AW_PROMPT_e1fc2cb2cbeaacc4_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
@@ -202,7 +207,7 @@ jobs:
cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/cache_memory_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_5d913d5c763dcde8_EOF'
+ cat << 'GH_AW_PROMPT_e1fc2cb2cbeaacc4_EOF'
Tools: add_comment(max:2), create_issue, create_discussion, create_pull_request_review_comment(max:5), submit_pull_request_review, add_labels, remove_labels, dispatch_workflow, missing_tool, missing_data, noop, send_slack_message
@@ -234,9 +239,9 @@ jobs:
{{/if}}
- GH_AW_PROMPT_5d913d5c763dcde8_EOF
+ GH_AW_PROMPT_e1fc2cb2cbeaacc4_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
- cat << 'GH_AW_PROMPT_5d913d5c763dcde8_EOF'
+ cat << 'GH_AW_PROMPT_e1fc2cb2cbeaacc4_EOF'
## Serena Code Analysis
@@ -274,7 +279,7 @@ jobs:
{{#runtime-import .github/workflows/shared/github-queries-mcp-script.md}}
{{#runtime-import .github/workflows/shared/mcp/serena-go.md}}
{{#runtime-import .github/workflows/smoke-copilot-arm.md}}
- GH_AW_PROMPT_5d913d5c763dcde8_EOF
+ GH_AW_PROMPT_e1fc2cb2cbeaacc4_EOF
} > "$GH_AW_PROMPT"
- name: Interpolate variables and render templates
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
@@ -530,12 +535,12 @@ jobs:
mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_b3b02bc8bedde255_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_947e130c0b26d5ea_EOF'
{"add_comment":{"allowed_repos":["github/gh-aw"],"hide_older_comments":true,"max":2},"add_labels":{"allowed":["smoke-copilot-arm"],"allowed_repos":["github/gh-aw"]},"create_discussion":{"category":"announcements","close_older_discussions":true,"expires":2,"fallback_to_issue":true,"labels":["ai-generated"],"max":1},"create_issue":{"close_older_issues":true,"close_older_key":"smoke-copilot-arm","expires":2,"group":true,"labels":["automation","testing"],"max":1},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"dispatch_workflow":{"max":1,"workflow_files":{"haiku-printer":".yml"},"workflows":["haiku-printer"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"remove_labels":{"allowed":["smoke"]},"send-slack-message":{"description":"Send a message to Slack (stub for testing)","inputs":{"message":{"description":"The message to send","required":false,"type":"string"}},"output":"Slack message stub executed!"},"submit_pull_request_review":{"max":1}}
- GH_AW_SAFE_OUTPUTS_CONFIG_b3b02bc8bedde255_EOF
+ GH_AW_SAFE_OUTPUTS_CONFIG_947e130c0b26d5ea_EOF
- name: Write Safe Outputs Tools
run: |
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_71157be718379f35_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_7a5b953e996d8298_EOF'
{
"description_suffixes": {
"add_comment": " CONSTRAINTS: Maximum 2 comment(s) can be added.",
@@ -592,8 +597,8 @@ jobs:
}
]
}
- GH_AW_SAFE_OUTPUTS_TOOLS_META_71157be718379f35_EOF
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_6b9e2ffc5e628cfb_EOF'
+ GH_AW_SAFE_OUTPUTS_TOOLS_META_7a5b953e996d8298_EOF
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_cad1a7b1918f47ef_EOF'
{
"add_comment": {
"defaultMax": 1,
@@ -823,7 +828,7 @@ jobs:
}
}
}
- GH_AW_SAFE_OUTPUTS_VALIDATION_6b9e2ffc5e628cfb_EOF
+ GH_AW_SAFE_OUTPUTS_VALIDATION_cad1a7b1918f47ef_EOF
node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs
- name: Generate Safe Outputs MCP Server Config
id: safe-outputs-config
@@ -868,7 +873,7 @@ jobs:
- name: Setup MCP Scripts Config
run: |
mkdir -p ${RUNNER_TEMP}/gh-aw/mcp-scripts/logs
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/tools.json << 'GH_AW_MCP_SCRIPTS_TOOLS_5f80dec2b93fd240_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/tools.json << 'GH_AW_MCP_SCRIPTS_TOOLS_1c701d2b9950333f_EOF'
{
"serverName": "mcpscripts",
"version": "1.0.0",
@@ -984,8 +989,8 @@ jobs:
}
]
}
- GH_AW_MCP_SCRIPTS_TOOLS_5f80dec2b93fd240_EOF
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/mcp-server.cjs << 'GH_AW_MCP_SCRIPTS_SERVER_9583ab3a98c30557_EOF'
+ GH_AW_MCP_SCRIPTS_TOOLS_1c701d2b9950333f_EOF
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/mcp-server.cjs << 'GH_AW_MCP_SCRIPTS_SERVER_c0a0a7288717268c_EOF'
const path = require("path");
const { startHttpServer } = require("./mcp_scripts_mcp_server_http.cjs");
const configPath = path.join(__dirname, "tools.json");
@@ -999,12 +1004,12 @@ jobs:
console.error("Failed to start mcp-scripts HTTP server:", error);
process.exit(1);
});
- GH_AW_MCP_SCRIPTS_SERVER_9583ab3a98c30557_EOF
+ GH_AW_MCP_SCRIPTS_SERVER_c0a0a7288717268c_EOF
chmod +x ${RUNNER_TEMP}/gh-aw/mcp-scripts/mcp-server.cjs
- name: Setup MCP Scripts Tool Files
run: |
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/gh.sh << 'GH_AW_MCP_SCRIPTS_SH_GH_487bcc3c1624a635_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/gh.sh << 'GH_AW_MCP_SCRIPTS_SH_GH_91488b82431e1a7f_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: gh
# Execute any gh CLI command. This tool is accessible as 'mcpscripts-gh'. Provide the full command after 'gh' (e.g., args: 'pr list --limit 5'). The tool will run: gh . Use single quotes ' for complex args to avoid shell interpretation issues.
@@ -1015,9 +1020,9 @@ jobs:
echo " token: ${GH_AW_GH_TOKEN:0:6}..."
GH_TOKEN="$GH_AW_GH_TOKEN" gh $INPUT_ARGS
- GH_AW_MCP_SCRIPTS_SH_GH_487bcc3c1624a635_EOF
+ GH_AW_MCP_SCRIPTS_SH_GH_91488b82431e1a7f_EOF
chmod +x ${RUNNER_TEMP}/gh-aw/mcp-scripts/gh.sh
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-discussion-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-DISCUSSION-QUERY_de6480930afd6152_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-discussion-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-DISCUSSION-QUERY_93e05781f9ca515e_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: github-discussion-query
# Query GitHub discussions with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.
@@ -1152,9 +1157,9 @@ jobs:
EOF
fi
- GH_AW_MCP_SCRIPTS_SH_GITHUB-DISCUSSION-QUERY_de6480930afd6152_EOF
+ GH_AW_MCP_SCRIPTS_SH_GITHUB-DISCUSSION-QUERY_93e05781f9ca515e_EOF
chmod +x ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-discussion-query.sh
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-issue-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-ISSUE-QUERY_728c50db158e2b32_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-issue-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-ISSUE-QUERY_c1c61a69acdb8d06_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: github-issue-query
# Query GitHub issues with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.
@@ -1233,9 +1238,9 @@ jobs:
fi
- GH_AW_MCP_SCRIPTS_SH_GITHUB-ISSUE-QUERY_728c50db158e2b32_EOF
+ GH_AW_MCP_SCRIPTS_SH_GITHUB-ISSUE-QUERY_c1c61a69acdb8d06_EOF
chmod +x ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-issue-query.sh
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-pr-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-PR-QUERY_288f75e4dc98f5a6_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-pr-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-PR-QUERY_f517760b3784f2a2_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: github-pr-query
# Query GitHub pull requests with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.
@@ -1320,7 +1325,7 @@ jobs:
fi
- GH_AW_MCP_SCRIPTS_SH_GITHUB-PR-QUERY_288f75e4dc98f5a6_EOF
+ GH_AW_MCP_SCRIPTS_SH_GITHUB-PR-QUERY_f517760b3784f2a2_EOF
chmod +x ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-pr-query.sh
- name: Generate MCP Scripts Server Config
@@ -1393,7 +1398,7 @@ jobs:
export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_MCP_SCRIPTS_PORT -e GH_AW_MCP_SCRIPTS_API_KEY -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -e GH_AW_GH_TOKEN -e GH_DEBUG -e GH_TOKEN -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.12'
mkdir -p /home/runner/.copilot
- cat << GH_AW_MCP_CONFIG_bbaab723be3e0d4f_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh
+ cat << GH_AW_MCP_CONFIG_baa1bb4a61e1bc9d_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh
{
"mcpServers": {
"agenticworkflows": {
@@ -1510,7 +1515,7 @@ jobs:
"payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
}
}
- GH_AW_MCP_CONFIG_bbaab723be3e0d4f_EOF
+ GH_AW_MCP_CONFIG_baa1bb4a61e1bc9d_EOF
- name: Download activation artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
diff --git a/.github/workflows/smoke-copilot-arm.md b/.github/workflows/smoke-copilot-arm.md
index 7c539c2d878..35564e5408c 100644
--- a/.github/workflows/smoke-copilot-arm.md
+++ b/.github/workflows/smoke-copilot-arm.md
@@ -106,6 +106,10 @@ safe-outputs:
run-failure: "📰 DEVELOPING STORY: [{workflow_name}]({run_url}) reports {status}. Our correspondents are investigating the incident..."
timeout-minutes: 15
strict: false
+observability:
+ otlp:
+ endpoint: ${{ secrets.GH_AW_OTEL_ENDPOINT }}
+ headers: ${{ secrets.GH_AW_OTEL_HEADERS }}
---
# Smoke Test: Copilot Engine Validation (ARM64)
diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml
index 7a0e924a4fa..3ca1ea35850 100644
--- a/.github/workflows/smoke-copilot.lock.yml
+++ b/.github/workflows/smoke-copilot.lock.yml
@@ -31,7 +31,7 @@
# - shared/mcp/serena.md
# - shared/reporting.md
#
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"a7b4d7bf4f02611637cd82a7a5f7c06048689e94db970e6f73d90a2673fdecc7","agent_id":"copilot"}
+# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"a905032d976816465ac3dca3ab19ecdf3acddb929861a5ff5984faffcab585e4","agent_id":"copilot"}
name: "Smoke Copilot"
"on":
@@ -60,6 +60,11 @@ concurrency:
run-name: "Smoke Copilot"
+env:
+ OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.GH_AW_OTEL_ENDPOINT }}
+ OTEL_SERVICE_NAME: gh-aw
+ OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.GH_AW_OTEL_HEADERS }}
+
jobs:
activation:
needs: pre_activation
@@ -199,9 +204,9 @@ jobs:
run: |
bash ${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh
{
- cat << 'GH_AW_PROMPT_9df51225daadb559_EOF'
+ cat << 'GH_AW_PROMPT_62c8abf1cc0f53ad_EOF'
- GH_AW_PROMPT_9df51225daadb559_EOF
+ GH_AW_PROMPT_62c8abf1cc0f53ad_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
@@ -209,7 +214,7 @@ jobs:
cat "${RUNNER_TEMP}/gh-aw/prompts/agentic_workflows_guide.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/cache_memory_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_9df51225daadb559_EOF'
+ cat << 'GH_AW_PROMPT_62c8abf1cc0f53ad_EOF'
Tools: add_comment(max:2), create_issue, create_discussion, create_pull_request_review_comment(max:5), submit_pull_request_review, reply_to_pull_request_review_comment(max:5), add_labels, remove_labels, set_issue_type, dispatch_workflow, missing_tool, missing_data, noop, send_slack_message
@@ -241,9 +246,9 @@ jobs:
{{/if}}
- GH_AW_PROMPT_9df51225daadb559_EOF
+ GH_AW_PROMPT_62c8abf1cc0f53ad_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
- cat << 'GH_AW_PROMPT_9df51225daadb559_EOF'
+ cat << 'GH_AW_PROMPT_62c8abf1cc0f53ad_EOF'
## Serena Code Analysis
@@ -282,7 +287,7 @@ jobs:
{{#runtime-import .github/workflows/shared/github-queries-mcp-script.md}}
{{#runtime-import .github/workflows/shared/mcp/serena-go.md}}
{{#runtime-import .github/workflows/smoke-copilot.md}}
- GH_AW_PROMPT_9df51225daadb559_EOF
+ GH_AW_PROMPT_62c8abf1cc0f53ad_EOF
} > "$GH_AW_PROMPT"
- name: Interpolate variables and render templates
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
@@ -538,12 +543,12 @@ jobs:
mkdir -p ${RUNNER_TEMP}/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_3c8a610621dc5cbf_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/config.json << 'GH_AW_SAFE_OUTPUTS_CONFIG_996bb8e28da5dfb7_EOF'
{"add_comment":{"allowed_repos":["github/gh-aw"],"hide_older_comments":true,"max":2},"add_labels":{"allowed":["smoke-copilot"],"allowed_repos":["github/gh-aw"]},"create_discussion":{"category":"announcements","close_older_discussions":true,"close_older_key":"smoke-copilot","expires":2,"fallback_to_issue":true,"labels":["ai-generated"],"max":1},"create_issue":{"close_older_issues":true,"close_older_key":"smoke-copilot","expires":2,"group":true,"labels":["automation","testing"],"max":1},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"dispatch_workflow":{"max":1,"workflow_files":{"haiku-printer":".yml"},"workflows":["haiku-printer"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"remove_labels":{"allowed":["smoke"]},"reply_to_pull_request_review_comment":{"max":5},"send-slack-message":{"description":"Send a message to Slack (stub for testing)","inputs":{"message":{"description":"The message to send","required":false,"type":"string"}},"output":"Slack message stub executed!"},"set_issue_type":{},"submit_pull_request_review":{"max":1}}
- GH_AW_SAFE_OUTPUTS_CONFIG_3c8a610621dc5cbf_EOF
+ GH_AW_SAFE_OUTPUTS_CONFIG_996bb8e28da5dfb7_EOF
- name: Write Safe Outputs Tools
run: |
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_d67ffee6fad53472_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/tools_meta.json << 'GH_AW_SAFE_OUTPUTS_TOOLS_META_d4e9fcd31c3eddcb_EOF'
{
"description_suffixes": {
"add_comment": " CONSTRAINTS: Maximum 2 comment(s) can be added.",
@@ -601,8 +606,8 @@ jobs:
}
]
}
- GH_AW_SAFE_OUTPUTS_TOOLS_META_d67ffee6fad53472_EOF
- cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_d8a24fe9ebf525ab_EOF'
+ GH_AW_SAFE_OUTPUTS_TOOLS_META_d4e9fcd31c3eddcb_EOF
+ cat > ${RUNNER_TEMP}/gh-aw/safeoutputs/validation.json << 'GH_AW_SAFE_OUTPUTS_VALIDATION_7d41b605be50b9cb_EOF'
{
"add_comment": {
"defaultMax": 1,
@@ -872,7 +877,7 @@ jobs:
}
}
}
- GH_AW_SAFE_OUTPUTS_VALIDATION_d8a24fe9ebf525ab_EOF
+ GH_AW_SAFE_OUTPUTS_VALIDATION_7d41b605be50b9cb_EOF
node ${RUNNER_TEMP}/gh-aw/actions/generate_safe_outputs_tools.cjs
- name: Generate Safe Outputs MCP Server Config
id: safe-outputs-config
@@ -917,7 +922,7 @@ jobs:
- name: Setup MCP Scripts Config
run: |
mkdir -p ${RUNNER_TEMP}/gh-aw/mcp-scripts/logs
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/tools.json << 'GH_AW_MCP_SCRIPTS_TOOLS_3e8f78b47058959a_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/tools.json << 'GH_AW_MCP_SCRIPTS_TOOLS_1e7561d526f43bda_EOF'
{
"serverName": "mcpscripts",
"version": "1.0.0",
@@ -1033,8 +1038,8 @@ jobs:
}
]
}
- GH_AW_MCP_SCRIPTS_TOOLS_3e8f78b47058959a_EOF
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/mcp-server.cjs << 'GH_AW_MCP_SCRIPTS_SERVER_e7b909a1866941c3_EOF'
+ GH_AW_MCP_SCRIPTS_TOOLS_1e7561d526f43bda_EOF
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/mcp-server.cjs << 'GH_AW_MCP_SCRIPTS_SERVER_a5255a3a8e9f133e_EOF'
const path = require("path");
const { startHttpServer } = require("./mcp_scripts_mcp_server_http.cjs");
const configPath = path.join(__dirname, "tools.json");
@@ -1048,12 +1053,12 @@ jobs:
console.error("Failed to start mcp-scripts HTTP server:", error);
process.exit(1);
});
- GH_AW_MCP_SCRIPTS_SERVER_e7b909a1866941c3_EOF
+ GH_AW_MCP_SCRIPTS_SERVER_a5255a3a8e9f133e_EOF
chmod +x ${RUNNER_TEMP}/gh-aw/mcp-scripts/mcp-server.cjs
- name: Setup MCP Scripts Tool Files
run: |
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/gh.sh << 'GH_AW_MCP_SCRIPTS_SH_GH_263ef6d96de89fb3_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/gh.sh << 'GH_AW_MCP_SCRIPTS_SH_GH_ba7386878a21d8cb_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: gh
# Execute any gh CLI command. This tool is accessible as 'mcpscripts-gh'. Provide the full command after 'gh' (e.g., args: 'pr list --limit 5'). The tool will run: gh . Use single quotes ' for complex args to avoid shell interpretation issues.
@@ -1064,9 +1069,9 @@ jobs:
echo " token: ${GH_AW_GH_TOKEN:0:6}..."
GH_TOKEN="$GH_AW_GH_TOKEN" gh $INPUT_ARGS
- GH_AW_MCP_SCRIPTS_SH_GH_263ef6d96de89fb3_EOF
+ GH_AW_MCP_SCRIPTS_SH_GH_ba7386878a21d8cb_EOF
chmod +x ${RUNNER_TEMP}/gh-aw/mcp-scripts/gh.sh
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-discussion-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-DISCUSSION-QUERY_05d4ab943fe86ce9_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-discussion-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-DISCUSSION-QUERY_4d7640a4c077e31c_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: github-discussion-query
# Query GitHub discussions with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.
@@ -1201,9 +1206,9 @@ jobs:
EOF
fi
- GH_AW_MCP_SCRIPTS_SH_GITHUB-DISCUSSION-QUERY_05d4ab943fe86ce9_EOF
+ GH_AW_MCP_SCRIPTS_SH_GITHUB-DISCUSSION-QUERY_4d7640a4c077e31c_EOF
chmod +x ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-discussion-query.sh
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-issue-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-ISSUE-QUERY_8ef0432b17b9641c_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-issue-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-ISSUE-QUERY_0641c15ff140ff12_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: github-issue-query
# Query GitHub issues with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.
@@ -1282,9 +1287,9 @@ jobs:
fi
- GH_AW_MCP_SCRIPTS_SH_GITHUB-ISSUE-QUERY_8ef0432b17b9641c_EOF
+ GH_AW_MCP_SCRIPTS_SH_GITHUB-ISSUE-QUERY_0641c15ff140ff12_EOF
chmod +x ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-issue-query.sh
- cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-pr-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-PR-QUERY_c889f4807956eb81_EOF'
+ cat > ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-pr-query.sh << 'GH_AW_MCP_SCRIPTS_SH_GITHUB-PR-QUERY_9ddf10ca0deacae4_EOF'
#!/bin/bash
# Auto-generated mcp-script tool: github-pr-query
# Query GitHub pull requests with jq filtering support. Without --jq, returns schema and data size info. Use --jq '.' to get all data, or specific jq expressions to filter.
@@ -1369,7 +1374,7 @@ jobs:
fi
- GH_AW_MCP_SCRIPTS_SH_GITHUB-PR-QUERY_c889f4807956eb81_EOF
+ GH_AW_MCP_SCRIPTS_SH_GITHUB-PR-QUERY_9ddf10ca0deacae4_EOF
chmod +x ${RUNNER_TEMP}/gh-aw/mcp-scripts/github-pr-query.sh
- name: Generate MCP Scripts Server Config
@@ -1440,7 +1445,7 @@ jobs:
export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_MCP_SCRIPTS_PORT -e GH_AW_MCP_SCRIPTS_API_KEY -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -e GH_AW_GH_TOKEN -e GH_DEBUG -e GH_TOKEN -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.12'
mkdir -p /home/runner/.copilot
- cat << GH_AW_MCP_CONFIG_7d1672508c35ebcf_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh
+ cat << GH_AW_MCP_CONFIG_c260f8029b966df4_EOF | bash ${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh
{
"mcpServers": {
"agenticworkflows": {
@@ -1560,7 +1565,7 @@ jobs:
"payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
}
}
- GH_AW_MCP_CONFIG_7d1672508c35ebcf_EOF
+ GH_AW_MCP_CONFIG_c260f8029b966df4_EOF
- name: Download activation artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
diff --git a/.github/workflows/smoke-copilot.md b/.github/workflows/smoke-copilot.md
index 93649992299..b476456956e 100644
--- a/.github/workflows/smoke-copilot.md
+++ b/.github/workflows/smoke-copilot.md
@@ -117,6 +117,10 @@ safe-outputs:
run-failure: "📰 DEVELOPING STORY: [{workflow_name}]({run_url}) reports {status}. Our correspondents are investigating the incident..."
timeout-minutes: 15
strict: false
+observability:
+ otlp:
+ endpoint: ${{ secrets.GH_AW_OTEL_ENDPOINT }}
+ headers: ${{ secrets.GH_AW_OTEL_HEADERS }}
---
# Smoke Test: Copilot Engine Validation
diff --git a/actions/setup/js/send_otlp_span.test.cjs b/actions/setup/js/send_otlp_span.test.cjs
index b0c58cbc4b3..7bbd3b0327e 100644
--- a/actions/setup/js/send_otlp_span.test.cjs
+++ b/actions/setup/js/send_otlp_span.test.cjs
@@ -435,6 +435,21 @@ describe("parseOTLPHeaders", () => {
expect(parseOTLPHeaders("Authorization=Bearer base64==")).toEqual({ Authorization: "Bearer base64==" });
});
+ it("parses Sentry OTLP header format (value contains space and embedded = sign)", () => {
+ // Sentry's OTLP auth header: x-sentry-auth: Sentry sentry_key=
+ // The value "Sentry sentry_key=abc123" contains both a space and an embedded =.
+ expect(parseOTLPHeaders("x-sentry-auth=Sentry sentry_key=abc123def456")).toEqual({
+ "x-sentry-auth": "Sentry sentry_key=abc123def456",
+ });
+ });
+
+ it("parses Sentry header combined with another header", () => {
+ expect(parseOTLPHeaders("x-sentry-auth=Sentry sentry_key=mykey,x-custom=value")).toEqual({
+ "x-sentry-auth": "Sentry sentry_key=mykey",
+ "x-custom": "value",
+ });
+ });
+
it("skips malformed pairs with no =", () => {
const result = parseOTLPHeaders("Valid=value,malformedNoEquals");
expect(result).toEqual({ Valid: "value" });
diff --git a/pkg/workflow/frontmatter_types.go b/pkg/workflow/frontmatter_types.go
index e3609f9f7ff..efd6b52ef27 100644
--- a/pkg/workflow/frontmatter_types.go
+++ b/pkg/workflow/frontmatter_types.go
@@ -144,7 +144,7 @@ type FrontmatterConfig struct {
// Core workflow fields
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
- Engine string `json:"engine,omitempty"`
+ Engine any `json:"engine,omitempty"`
Source string `json:"source,omitempty"`
TrackerID string `json:"tracker-id,omitempty"`
Version string `json:"version,omitempty"`
@@ -272,7 +272,7 @@ func ParseFrontmatterConfig(frontmatter map[string]any) (*FrontmatterConfig, err
}
}
- frontmatterTypesLog.Printf("Successfully parsed frontmatter config: name=%s, engine=%s", config.Name, config.Engine)
+ frontmatterTypesLog.Printf("Successfully parsed frontmatter config: name=%s, engine=%v", config.Name, config.Engine)
return &config, nil
}
@@ -541,7 +541,7 @@ func (fc *FrontmatterConfig) ToMap() map[string]any {
if fc.Description != "" {
result["description"] = fc.Description
}
- if fc.Engine != "" {
+ if fc.Engine != nil {
result["engine"] = fc.Engine
}
if fc.Source != "" {
diff --git a/pkg/workflow/observability_otlp.go b/pkg/workflow/observability_otlp.go
index c1463e59cde..bf92fd33a22 100644
--- a/pkg/workflow/observability_otlp.go
+++ b/pkg/workflow/observability_otlp.go
@@ -48,6 +48,37 @@ func getOTLPEndpointEnvValue(config *FrontmatterConfig) string {
return config.Observability.OTLP.Endpoint
}
+// extractOTLPConfigFromRaw reads OTLP endpoint and headers directly from the raw
+// frontmatter map[string]any. This avoids dependence on ParseFrontmatterConfig
+// succeeding — that function may fail for workflows with complex tool configurations
+// (e.g. engine objects, array-style bash configs), which would leave ParsedFrontmatter
+// nil and prevent OTLP injection.
+func extractOTLPConfigFromRaw(frontmatter map[string]any) (endpoint, headers string) {
+ obs, ok := frontmatter["observability"]
+ if !ok {
+ return
+ }
+ obsMap, ok := obs.(map[string]any)
+ if !ok {
+ return
+ }
+ otlp, ok := obsMap["otlp"]
+ if !ok {
+ return
+ }
+ otlpMap, ok := otlp.(map[string]any)
+ if !ok {
+ return
+ }
+ if ep, ok := otlpMap["endpoint"].(string); ok {
+ endpoint = ep
+ }
+ if h, ok := otlpMap["headers"].(string); ok {
+ headers = h
+ }
+ return
+}
+
// generateOTLPConclusionSpanStep generates a GitHub Actions step that sends an OTLP
// conclusion span from a downstream job (safe_outputs or conclusion).
//
@@ -82,7 +113,15 @@ func generateOTLPConclusionSpanStep(spanName string) string {
//
// When no OTLP endpoint is configured the function is a no-op.
func (c *Compiler) injectOTLPConfig(workflowData *WorkflowData) {
- endpoint := getOTLPEndpointEnvValue(workflowData.ParsedFrontmatter)
+ // Read OTLP config from the raw frontmatter map so that injection works even
+ // when ParseFrontmatterConfig failed (e.g. due to complex tool configs).
+ endpoint, headers := extractOTLPConfigFromRaw(workflowData.RawFrontmatter)
+
+ // Fall back to ParsedFrontmatter when the raw map didn't yield an endpoint.
+ if endpoint == "" {
+ endpoint = getOTLPEndpointEnvValue(workflowData.ParsedFrontmatter)
+ }
+
if endpoint == "" {
return
}
@@ -102,7 +141,13 @@ func (c *Compiler) injectOTLPConfig(workflowData *WorkflowData) {
otlpEnvLines := fmt.Sprintf(" OTEL_EXPORTER_OTLP_ENDPOINT: %s\n OTEL_SERVICE_NAME: gh-aw", endpoint)
// 3. Inject OTEL_EXPORTER_OTLP_HEADERS when configured.
- if headers := workflowData.ParsedFrontmatter.Observability.OTLP.Headers; headers != "" {
+ // Prefer raw frontmatter value (already read above); fall back to ParsedFrontmatter.
+ if headers == "" && workflowData.ParsedFrontmatter != nil &&
+ workflowData.ParsedFrontmatter.Observability != nil &&
+ workflowData.ParsedFrontmatter.Observability.OTLP != nil {
+ headers = workflowData.ParsedFrontmatter.Observability.OTLP.Headers
+ }
+ if headers != "" {
otlpEnvLines += "\n OTEL_EXPORTER_OTLP_HEADERS: " + headers
otlpLog.Printf("Injected OTEL_EXPORTER_OTLP_HEADERS env var")
}
diff --git a/pkg/workflow/observability_otlp_test.go b/pkg/workflow/observability_otlp_test.go
index 4fada70f060..42779eab0ed 100644
--- a/pkg/workflow/observability_otlp_test.go
+++ b/pkg/workflow/observability_otlp_test.go
@@ -424,3 +424,123 @@ func TestGenerateOTLPConclusionSpanStep(t *testing.T) {
assert.Contains(t, step, "gh-aw.job.conclusion", "script should use the given span name")
})
}
+
+// TestExtractOTLPConfigFromRaw verifies direct raw-frontmatter OTLP extraction.
+func TestExtractOTLPConfigFromRaw(t *testing.T) {
+ tests := []struct {
+ name string
+ frontmatter map[string]any
+ wantEndpoint string
+ wantHeaders string
+ }{
+ {
+ name: "nil frontmatter",
+ frontmatter: nil,
+ },
+ {
+ name: "empty frontmatter",
+ frontmatter: map[string]any{},
+ },
+ {
+ name: "no observability key",
+ frontmatter: map[string]any{"name": "test"},
+ },
+ {
+ name: "observability without otlp",
+ frontmatter: map[string]any{
+ "observability": map[string]any{"job-summary": "on"},
+ },
+ },
+ {
+ name: "observability.otlp with endpoint",
+ frontmatter: map[string]any{
+ "observability": map[string]any{
+ "otlp": map[string]any{"endpoint": "https://traces.example.com:4317"},
+ },
+ },
+ wantEndpoint: "https://traces.example.com:4317",
+ },
+ {
+ name: "observability.otlp with secret expression endpoint",
+ frontmatter: map[string]any{
+ "observability": map[string]any{
+ "otlp": map[string]any{"endpoint": "${{ secrets.GH_AW_OTEL_ENDPOINT }}"},
+ },
+ },
+ wantEndpoint: "${{ secrets.GH_AW_OTEL_ENDPOINT }}",
+ },
+ {
+ name: "observability.otlp with endpoint and headers",
+ frontmatter: map[string]any{
+ "observability": map[string]any{
+ "otlp": map[string]any{
+ "endpoint": "https://traces.example.com",
+ "headers": "${{ secrets.GH_AW_OTEL_HEADERS }}",
+ },
+ },
+ },
+ wantEndpoint: "https://traces.example.com",
+ wantHeaders: "${{ secrets.GH_AW_OTEL_HEADERS }}",
+ },
+ {
+ name: "Sentry-style header with space in value",
+ frontmatter: map[string]any{
+ "observability": map[string]any{
+ "otlp": map[string]any{
+ "endpoint": "https://sentry.io/api/123/envelope/",
+ "headers": "x-sentry-auth=Sentry sentry_key=abc123",
+ },
+ },
+ },
+ wantEndpoint: "https://sentry.io/api/123/envelope/",
+ wantHeaders: "x-sentry-auth=Sentry sentry_key=abc123",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ gotEndpoint, gotHeaders := extractOTLPConfigFromRaw(tt.frontmatter)
+ assert.Equal(t, tt.wantEndpoint, gotEndpoint, "endpoint")
+ assert.Equal(t, tt.wantHeaders, gotHeaders, "headers")
+ })
+ }
+}
+
+// TestInjectOTLPConfig_RawFrontmatterFallback verifies that injectOTLPConfig works
+// when ParsedFrontmatter is nil (e.g. complex engine objects cause ParseFrontmatterConfig
+// to fail) but the raw frontmatter contains valid OTLP configuration.
+func TestInjectOTLPConfig_RawFrontmatterFallback(t *testing.T) {
+ c := &Compiler{}
+
+ t.Run("injects OTLP from raw frontmatter when ParsedFrontmatter is nil", func(t *testing.T) {
+ wd := &WorkflowData{
+ ParsedFrontmatter: nil, // simulates ParseFrontmatterConfig failure
+ RawFrontmatter: map[string]any{
+ "observability": map[string]any{
+ "otlp": map[string]any{
+ "endpoint": "${{ secrets.GH_AW_OTEL_ENDPOINT }}",
+ "headers": "${{ secrets.GH_AW_OTEL_HEADERS }}",
+ },
+ },
+ // Simulate complex engine object that would cause ParseFrontmatterConfig to fail.
+ "engine": map[string]any{"id": "copilot", "max-continuations": 2},
+ },
+ }
+ c.injectOTLPConfig(wd)
+
+ require.NotEmpty(t, wd.Env, "Env should be set even without ParsedFrontmatter")
+ assert.Contains(t, wd.Env, "OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.GH_AW_OTEL_ENDPOINT }}", "endpoint should be injected from raw")
+ assert.Contains(t, wd.Env, "OTEL_SERVICE_NAME: gh-aw", "service name should be set")
+ assert.Contains(t, wd.Env, "OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.GH_AW_OTEL_HEADERS }}", "headers should be injected from raw")
+ })
+
+ t.Run("no-op when neither raw nor parsed frontmatter has OTLP", func(t *testing.T) {
+ wd := &WorkflowData{
+ ParsedFrontmatter: nil,
+ RawFrontmatter: map[string]any{"name": "my-workflow"},
+ }
+ c.injectOTLPConfig(wd)
+ assert.Empty(t, wd.Env, "Env should remain empty")
+ assert.Nil(t, wd.NetworkPermissions, "NetworkPermissions should remain nil")
+ })
+}
From 571fef3687eff613381ea575d7c914500c2d5d4b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 4 Apr 2026 15:18:22 +0000
Subject: [PATCH 16/16] fix: add comment to Engine any field; fix em dash in
comment
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/21afe94c-2d9a-4d15-9dab-6859ad6cc23b
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
pkg/workflow/frontmatter_types.go | 8 ++++++--
pkg/workflow/observability_otlp.go | 2 +-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/pkg/workflow/frontmatter_types.go b/pkg/workflow/frontmatter_types.go
index efd6b52ef27..2ae08be7a61 100644
--- a/pkg/workflow/frontmatter_types.go
+++ b/pkg/workflow/frontmatter_types.go
@@ -142,8 +142,12 @@ type ObservabilityConfig struct {
// This provides compile-time type safety and clearer error messages compared to map[string]any
type FrontmatterConfig struct {
// Core workflow fields
- Name string `json:"name,omitempty"`
- Description string `json:"description,omitempty"`
+ Name string `json:"name,omitempty"`
+ Description string `json:"description,omitempty"`
+ // Engine accepts both a plain string engine name (e.g. "copilot") and an object-style
+ // configuration (e.g. {id: copilot, max-continuations: 2}). Using any prevents
+ // JSON unmarshal failures when the engine is an object, which would otherwise cause
+ // ParseFrontmatterConfig to return nil and break features that depend on it (e.g. OTLP).
Engine any `json:"engine,omitempty"`
Source string `json:"source,omitempty"`
TrackerID string `json:"tracker-id,omitempty"`
diff --git a/pkg/workflow/observability_otlp.go b/pkg/workflow/observability_otlp.go
index bf92fd33a22..bcc84fa9006 100644
--- a/pkg/workflow/observability_otlp.go
+++ b/pkg/workflow/observability_otlp.go
@@ -50,7 +50,7 @@ func getOTLPEndpointEnvValue(config *FrontmatterConfig) string {
// extractOTLPConfigFromRaw reads OTLP endpoint and headers directly from the raw
// frontmatter map[string]any. This avoids dependence on ParseFrontmatterConfig
-// succeeding — that function may fail for workflows with complex tool configurations
+// succeeding -- that function may fail for workflows with complex tool configurations
// (e.g. engine objects, array-style bash configs), which would leave ParsedFrontmatter
// nil and prevent OTLP injection.
func extractOTLPConfigFromRaw(frontmatter map[string]any) (endpoint, headers string) {