Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ce1a3ae
Plan deterministic trace graders
Copilot Aug 22, 2026
de6658f
Add initial deterministic trace graders
Copilot Aug 22, 2026
4b4de8a
docs(adr): add draft ADR-54678 for deterministic trace grading framework
github-actions[bot] Aug 22, 2026
9eb6028
Merge branch 'main' into copilot/implement-deterministic-trace-graders
github-actions[bot] Aug 22, 2026
0d6a86e
Harden trace grader runtime isolation and manifest transport
Copilot Aug 22, 2026
53938a6
Merge branch 'main' into copilot/implement-deterministic-trace-graders
github-actions[bot] Aug 22, 2026
1a1b44d
Merge remote-tracking branch 'origin/main' into copilot/implement-det…
Copilot Aug 22, 2026
ed01ef4
Refresh branch and fix trace graders JS type casts
Copilot Aug 22, 2026
ef94444
Merge remote-tracking branch 'origin/main' into copilot/implement-det…
Copilot Aug 22, 2026
dce434c
Integrate experiment context into graders and evals
Copilot Aug 22, 2026
7a02562
Allow experiments metrics to reference grader results
Copilot Aug 22, 2026
b0ad3c7
Mark trace graders as experimental
Copilot Aug 22, 2026
673bba9
Merge branch 'main' into copilot/implement-deterministic-trace-graders
github-actions[bot] Aug 22, 2026
1781737
Merge branch 'main' into copilot/implement-deterministic-trace-graders
github-actions[bot] Aug 22, 2026
2906c4a
fix trace grader sandbox embedding and script-size contract
Copilot Aug 22, 2026
803ce40
test: add graders integration workflow coverage
Copilot Aug 22, 2026
ba7aae8
Merge branch 'main' into copilot/implement-deterministic-trace-graders
github-actions[bot] Aug 22, 2026
9baed09
Merge branch 'main' into copilot/implement-deterministic-trace-graders
github-actions[bot] Aug 22, 2026
f377fa2
Merge branch 'main' into copilot/implement-deterministic-trace-graders
github-actions[bot] Aug 22, 2026
00ca65f
Harden trace grader log parsing and summary output
Copilot Aug 22, 2026
9fff955
Harden trace grader fallback parsing and summary safety
Copilot Aug 22, 2026
096aa3e
chore: start triage for unresolved review feedback
Copilot Aug 22, 2026
455639f
fix grader sandbox clone fallback and parser edge cases
Copilot Aug 22, 2026
1d3542e
fix: rename grader clone helper to explicit clone-or-undefined
Copilot Aug 22, 2026
4e303c5
Merge branch 'main' into copilot/implement-deterministic-trace-graders
github-actions[bot] Aug 22, 2026
6c61d48
refactor: rename trace graders wording to graders
Copilot Aug 22, 2026
1b3d870
Merge remote-tracking branch 'origin/main' into copilot/implement-det…
Copilot Aug 22, 2026
5131cd9
refactor: rename grader implementation id
Copilot Aug 22, 2026
782f56d
docs: add graders specification
Copilot Aug 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: rename trace graders wording to graders
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
  • Loading branch information
Copilot and pelikhan authored Aug 22, 2026
commit 6c61d489a0e1884296d8c23e967c20ed90326a68
2 changes: 1 addition & 1 deletion actions/setup/js/trace_graders.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ async function main(manifestB64, execSpecB64) {
}

// Step summary
core.summary.addHeading("Trace Graders", 3);
core.summary.addHeading("Graders", 3);
const tableResults = results.filter(r => r.status !== "unavailable");
if (tableResults.length > 0) {
const rows = tableResults.map(r => {
Expand Down
2 changes: 1 addition & 1 deletion actions/setup/sh/prepare_threat_detection_files.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ for artifact_pattern in aw-*.patch aw-*.bundle; do
done
done

# Copy grader manifest and results if present (deterministic trace graders)
# Copy grader manifest and results if present (deterministic graders)
GRADER_SOURCE_DIR="${SOURCE_DIR}/agent/graders"
if [ -d "${GRADER_SOURCE_DIR}" ]; then
GRADER_DETECTION_DIR="${DETECTION_DIR}/agent/graders"
Expand Down
6 changes: 3 additions & 3 deletions docs/src/content/docs/reference/trace-graders.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
title: Trace Graders
title: Graders
description: Deterministic metrics computed from agent execution traces
---

Trace graders compute deterministic metrics from post-agent execution trace files (token usage, MCP gateway logs, agent output) without LLM calls or network access. Results are persisted in the agent artifact for downstream consumption by detection jobs and reporting tools.
Graders compute deterministic metrics from post-agent execution trace files (token usage, MCP gateway logs, agent output) without LLM calls or network access. Results are persisted in the agent artifact for downstream consumption by detection jobs and reporting tools.

:::caution[Experimental]
Trace graders are an experimental feature.
Graders are an experimental feature.
:::

## Quick start
Expand Down
2 changes: 1 addition & 1 deletion pkg/parser/schemas/main_workflow_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -12743,7 +12743,7 @@
"examples": ["gpt-5.4", "claude-3-5-sonnet-20241022", "gpt-4"]
},
"graders": {
"description": "\u26a0\ufe0f Experimental. Deterministic trace graders to compute post-agent metrics from execution artifacts. Map keys are grader IDs. Built-in graders can be configured by ID; custom graders require a script.",
"description": "\u26a0\ufe0f Experimental. Deterministic graders to compute post-agent metrics from execution artifacts. Map keys are grader IDs. Built-in graders can be configured by ID; custom graders require a script.",
"type": "object",
"propertyNames": {
"pattern": "^[a-z][a-z0-9-]{0,63}$",
Expand Down
2 changes: 1 addition & 1 deletion pkg/workflow/compiler_orchestrator_workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ func (c *Compiler) extractAdditionalConfigurations(
}
workflowData.Evals = evalsConfig

// Extract deterministic trace graders configuration.
// Extract deterministic graders configuration.
gradersConfig, err := c.parseGradersFromFrontmatter(frontmatter)
if err != nil {
return fmt.Errorf("invalid graders configuration: %w", err)
Expand Down
6 changes: 3 additions & 3 deletions pkg/workflow/compiler_yaml_graders.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
var compilerYamlGradersLog = logger.New("workflow:compiler_yaml_graders")

// generateGradersStep emits an always() post-agent step that runs deterministic
// trace graders. The step executes after secret redaction / summary steps and before
// graders. The step executes after secret redaction / summary steps and before
// the unified artifact upload so results are included in the agent artifact.
//
// The step is only emitted when graders are configured (graders: in frontmatter).
Expand Down Expand Up @@ -43,7 +43,7 @@ func (c *Compiler) generateGradersStep(yaml *strings.Builder, data *WorkflowData
}
execB64 := base64.StdEncoding.EncodeToString(execJSON)

yaml.WriteString(" - name: Run trace graders\n")
yaml.WriteString(" - name: Run graders\n")
yaml.WriteString(" if: always()\n")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: manifest escaping is incomplete — backslash before single-quote breaks the JS string literal

escapedManifest := strings.ReplaceAll(string(manifestJSON), "'", "\\'")
fmt.Fprintf(yaml, "            await main('%s', '%s');\n", escapedManifest, execB64)

JSON can contain \\ (an escaped backslash in a string value). After only escaping ', the sequence \\' in the original JSON becomes \\\' — the JavaScript parser sees an escaped backslash (\\) followed by an unescaped single quote that terminates the string literal, causing a syntax error or silent truncation.

Fix: escape backslashes first, then single quotes:

escaped := strings.ReplaceAll(string(manifestJSON), `\`, `\\`)
escaped  = strings.ReplaceAll(escaped, "'", `\'`)

@copilot please address this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ The manifest JSON escaping here uses single-quote escaping before YAML embedding, but grader names or descriptions containing backslashes followed by a quote character could break the generated JavaScript at runtime. Consider using base64 encoding for the full manifest (similar to what's done for the exec spec) to make injection impossible.

yaml.WriteString(" continue-on-error: true\n")
fmt.Fprintf(yaml, " uses: %s\n", getCachedActionPin("actions/github-script", data))
Expand All @@ -54,7 +54,7 @@ func (c *Compiler) generateGradersStep(yaml *strings.Builder, data *WorkflowData
yaml.WriteString(" const { main } = require('" + SetupActionDestination + "/trace_graders.cjs');\n")
fmt.Fprintf(yaml, " await main('%s', '%s');\n", manifestB64, execB64)

compilerYamlGradersLog.Print("Generated trace graders step")
compilerYamlGradersLog.Print("Generated graders step")
}

// graderManifestEntry represents a single grader in the serialized manifest.
Expand Down
2 changes: 1 addition & 1 deletion pkg/workflow/compiler_yaml_post_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func (c *Compiler) generatePostAgentCollectionAndUpload(yaml *strings.Builder, d
// Emit all GITHUB_STEP_SUMMARY log-parsing steps.
c.generateSummarySteps(yaml, data, engine)

// Run deterministic trace graders after trace data is available.
// Run deterministic graders after trace data is available.
c.generateGradersStep(yaml, data)

// Re-scan grader output files for leaked secrets when custom grader scripts
Expand Down
2 changes: 1 addition & 1 deletion pkg/workflow/frontmatter_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ type FrontmatterConfig struct {
// engine-config / runs-on overrides.
Evals any `json:"evals,omitempty"`

// Graders configures deterministic trace graders that compute metrics from
// Graders configures deterministic graders that compute metrics from
// post-agent trace files. Can be {} for zero-config (all built-ins) or a map
// of grader IDs with optional enabled/script overrides.
Graders any `json:"graders,omitempty"`
Expand Down
4 changes: 2 additions & 2 deletions pkg/workflow/graders_config.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Package workflow - Deterministic trace graders configuration types and parser.
// Package workflow - Deterministic graders configuration types and parser.
package workflow

import (
Expand Down Expand Up @@ -83,7 +83,7 @@ func (g *GraderDefinition) ScriptDigest() string {
return hex.EncodeToString(h[:])
}

// GradersConfig holds the configuration for deterministic trace graders declared
// GradersConfig holds the configuration for deterministic graders declared
// in workflow frontmatter. Graders run as an always() post-agent step in the agent job.
type GradersConfig struct {
// Graders is the map of grader ID to definition.
Expand Down
6 changes: 3 additions & 3 deletions pkg/workflow/graders_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,8 @@ func TestGenerateGradersStep_Present(t *testing.T) {
}
c.generateGradersStep(&yaml, data)
output := yaml.String()
if !strings.Contains(output, "Run trace graders") {
t.Fatal("expected step name 'Run trace graders'")
if !strings.Contains(output, "Run graders") {
t.Fatal("expected step name 'Run graders'")
}
if !strings.Contains(output, "if: always()") {
t.Fatal("expected always() condition")
Expand Down Expand Up @@ -374,7 +374,7 @@ func TestGenerateGradersStep_BeforeArtifactUpload(t *testing.T) {
yaml.WriteString(" - name: Upload agent artifacts\n")

output := yaml.String()
graderIdx := strings.Index(output, "Run trace graders")
graderIdx := strings.Index(output, "Run graders")
uploadIdx := strings.Index(output, "Upload agent artifacts")
if graderIdx < 0 || uploadIdx < 0 {
t.Fatal("expected both steps to be present")
Expand Down
2 changes: 1 addition & 1 deletion pkg/workflow/graders_workflow_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ experiments:
require.NoError(t, err)
yaml := string(compiled)

assert.Contains(t, yaml, "Run trace graders")
assert.Contains(t, yaml, "Run graders")
assert.Contains(t, yaml, "trace_graders.cjs")
assert.Contains(t, yaml, "grader:retries")
assert.Contains(t, yaml, "graders.custom-score.value")
Expand Down
2 changes: 1 addition & 1 deletion pkg/workflow/workflow_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ type WorkflowData struct {
ContainerPinMappings map[string]string // container-pin redirect table from aw.json container_pins: maps source image → replacement image
GHES bool // select action versions compatible with GitHub Enterprise Server
Evals *EvalsConfig // BinEval evaluation configuration parsed from frontmatter evals field
Graders *GradersConfig // Deterministic trace graders configuration parsed from frontmatter graders field
Graders *GradersConfig // Deterministic graders configuration parsed from frontmatter graders field
ExcludedEnv []string // additional env var names to exclude from agent container via AWF --exclude-env (from frontmatter excluded-env field)
}

Expand Down
Loading