From 5f2c3bbffadb00410d2597c54987f3266b77e1f1 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 21 Jul 2026 08:01:31 +0000
Subject: [PATCH 1/8] Initial plan


From 89dbca89f49b150ff2cc970f791e2a852c5375f4 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 21 Jul 2026 08:15:19 +0000
Subject: [PATCH 2/8] fix: guard conclude_threat_detection.sh against
 threat-detect when RUN_DETECTION=false

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 actions/setup/sh/conclude_threat_detection.sh |  8 +++-
 .../threat_detection_conclude_script_test.go  | 46 +++++++++++++++++++
 2 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/actions/setup/sh/conclude_threat_detection.sh b/actions/setup/sh/conclude_threat_detection.sh
index e3159664639..d515d64b168 100755
--- a/actions/setup/sh/conclude_threat_detection.sh
+++ b/actions/setup/sh/conclude_threat_detection.sh
@@ -10,7 +10,13 @@ DETECTION_STATUS_PREFIX="THREAT_DETECTION_STATUS:"
 continue_on_error="${GH_AW_DETECTION_CONTINUE_ON_ERROR:-true}"
 continue_on_error="$(echo "${continue_on_error}" | tr '[:upper:]' '[:lower:]')"
 
-if [ "${RUN_DETECTION:-false}" = "true" ] && [ ! -f "${RESULT_FILE}" ]; then
+if [ "${RUN_DETECTION:-false}" != "true" ]; then
+  echo "conclusion=skipped" >> "${GITHUB_OUTPUT}"
+  echo "GH_AW_DETECTION_CONCLUSION=skipped" >> "${GITHUB_ENV}"
+  exit 0
+fi
+
+if [ ! -f "${RESULT_FILE}" ]; then
   detection_status=""
   if [ -f "${DETECTION_LOG_FILE}" ]; then
     detection_status="$(grep "${DETECTION_STATUS_PREFIX}" "${DETECTION_LOG_FILE}" | tail -n 1 || true)"
diff --git a/pkg/workflow/threat_detection_conclude_script_test.go b/pkg/workflow/threat_detection_conclude_script_test.go
index 902fd51d027..360a685f474 100644
--- a/pkg/workflow/threat_detection_conclude_script_test.go
+++ b/pkg/workflow/threat_detection_conclude_script_test.go
@@ -108,6 +108,52 @@ func TestConcludeThreatDetectionScript_MissingResultSurfacesDetectorStatus(t *te
 	}
 }
 
+func TestConcludeThreatDetectionScript_SkippedWhenRunDetectionFalse(t *testing.T) {
+	tmpDir := t.TempDir()
+	scriptPath := filepath.Join("..", "..", "actions", "setup", "sh", "conclude_threat_detection.sh")
+	outputFile := filepath.Join(tmpDir, "github_output.txt")
+	envFile := filepath.Join(tmpDir, "github_env.txt")
+	// No result file written — threat-detect is not installed — both should be irrelevant.
+	missingResult := filepath.Join(tmpDir, "missing_detection_result.json")
+
+	// Use a PATH that does not include threat-detect by prepending a
+	// sentinel bin dir that contains no executables. The guard must
+	// exit before ever reaching the threat-detect invocation.
+	emptyBinDir := filepath.Join(tmpDir, "empty-bin")
+	if err := os.MkdirAll(emptyBinDir, 0755); err != nil {
+		t.Fatalf("failed to create empty bin dir: %v", err)
+	}
+
+	cmd := exec.Command("bash", scriptPath, missingResult)
+	cmd.Env = append(os.Environ(),
+		"RUN_DETECTION=false",
+		"GITHUB_OUTPUT="+outputFile,
+		"GITHUB_ENV="+envFile,
+		"PATH="+emptyBinDir+":"+os.Getenv("PATH"),
+	)
+
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("script should exit 0 when RUN_DETECTION=false: %v\nOutput: %s", err, out)
+	}
+
+	outputData, err := os.ReadFile(outputFile)
+	if err != nil {
+		t.Fatalf("failed to read GITHUB_OUTPUT: %v", err)
+	}
+	if !strings.Contains(string(outputData), "conclusion=skipped") {
+		t.Fatalf("expected conclusion=skipped in GITHUB_OUTPUT, got: %s", outputData)
+	}
+
+	envData, err := os.ReadFile(envFile)
+	if err != nil {
+		t.Fatalf("failed to read GITHUB_ENV: %v", err)
+	}
+	if !strings.Contains(string(envData), "GH_AW_DETECTION_CONCLUSION=skipped") {
+		t.Fatalf("expected GH_AW_DETECTION_CONCLUSION=skipped in GITHUB_ENV, got: %s", envData)
+	}
+}
+
 func TestConcludeThreatDetectionScript_InvokesThreatDetectConclude(t *testing.T) {
 	tmpDir := t.TempDir()
 	scriptPath := filepath.Join("..", "..", "actions", "setup", "sh", "conclude_threat_detection.sh")

From 62eaccaae3b1d67643e56658e884fe9814285348 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 21 Jul 2026 09:25:54 +0000
Subject: [PATCH 3/8] fix: emit success=true and reason= on skipped detection
 path to preserve output contract

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
---
 actions/setup/sh/conclude_threat_detection.sh |  3 +++
 .../threat_detection_conclude_script_test.go  | 19 +++++++++++++++----
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/actions/setup/sh/conclude_threat_detection.sh b/actions/setup/sh/conclude_threat_detection.sh
index d515d64b168..0863d232731 100755
--- a/actions/setup/sh/conclude_threat_detection.sh
+++ b/actions/setup/sh/conclude_threat_detection.sh
@@ -12,7 +12,10 @@ continue_on_error="$(echo "${continue_on_error}" | tr '[:upper:]' '[:lower:]')"
 
 if [ "${RUN_DETECTION:-false}" != "true" ]; then
   echo "conclusion=skipped" >> "${GITHUB_OUTPUT}"
+  echo "success=true" >> "${GITHUB_OUTPUT}"
+  echo "reason=" >> "${GITHUB_OUTPUT}"
   echo "GH_AW_DETECTION_CONCLUSION=skipped" >> "${GITHUB_ENV}"
+  echo "GH_AW_DETECTION_REASON=" >> "${GITHUB_ENV}"
   exit 0
 fi
 
diff --git a/pkg/workflow/threat_detection_conclude_script_test.go b/pkg/workflow/threat_detection_conclude_script_test.go
index 360a685f474..110cd70dba2 100644
--- a/pkg/workflow/threat_detection_conclude_script_test.go
+++ b/pkg/workflow/threat_detection_conclude_script_test.go
@@ -141,16 +141,27 @@ func TestConcludeThreatDetectionScript_SkippedWhenRunDetectionFalse(t *testing.T
 	if err != nil {
 		t.Fatalf("failed to read GITHUB_OUTPUT: %v", err)
 	}
-	if !strings.Contains(string(outputData), "conclusion=skipped") {
-		t.Fatalf("expected conclusion=skipped in GITHUB_OUTPUT, got: %s", outputData)
+	outputText := string(outputData)
+	if !strings.Contains(outputText, "conclusion=skipped") {
+		t.Fatalf("expected conclusion=skipped in GITHUB_OUTPUT, got: %s", outputText)
+	}
+	if !strings.Contains(outputText, "success=true") {
+		t.Fatalf("expected success=true in GITHUB_OUTPUT, got: %s", outputText)
+	}
+	if !strings.Contains(outputText, "reason=") {
+		t.Fatalf("expected reason= in GITHUB_OUTPUT, got: %s", outputText)
 	}
 
 	envData, err := os.ReadFile(envFile)
 	if err != nil {
 		t.Fatalf("failed to read GITHUB_ENV: %v", err)
 	}
-	if !strings.Contains(string(envData), "GH_AW_DETECTION_CONCLUSION=skipped") {
-		t.Fatalf("expected GH_AW_DETECTION_CONCLUSION=skipped in GITHUB_ENV, got: %s", envData)
+	envText := string(envData)
+	if !strings.Contains(envText, "GH_AW_DETECTION_CONCLUSION=skipped") {
+		t.Fatalf("expected GH_AW_DETECTION_CONCLUSION=skipped in GITHUB_ENV, got: %s", envText)
+	}
+	if !strings.Contains(envText, "GH_AW_DETECTION_REASON=") {
+		t.Fatalf("expected GH_AW_DETECTION_REASON= in GITHUB_ENV, got: %s", envText)
 	}
 }
 

From 07574be965b4658b83c5bc37349aaadc54549998 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 21 Jul 2026 11:58:45 +0000
Subject: [PATCH 4/8] fix: remove GITHUB_ENV writes from skipped detection
 guard, use output only

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 actions/setup/sh/conclude_threat_detection.sh      |  2 --
 .../threat_detection_conclude_script_test.go       | 14 --------------
 2 files changed, 16 deletions(-)

diff --git a/actions/setup/sh/conclude_threat_detection.sh b/actions/setup/sh/conclude_threat_detection.sh
index 0863d232731..c4e685be41b 100755
--- a/actions/setup/sh/conclude_threat_detection.sh
+++ b/actions/setup/sh/conclude_threat_detection.sh
@@ -14,8 +14,6 @@ if [ "${RUN_DETECTION:-false}" != "true" ]; then
   echo "conclusion=skipped" >> "${GITHUB_OUTPUT}"
   echo "success=true" >> "${GITHUB_OUTPUT}"
   echo "reason=" >> "${GITHUB_OUTPUT}"
-  echo "GH_AW_DETECTION_CONCLUSION=skipped" >> "${GITHUB_ENV}"
-  echo "GH_AW_DETECTION_REASON=" >> "${GITHUB_ENV}"
   exit 0
 fi
 
diff --git a/pkg/workflow/threat_detection_conclude_script_test.go b/pkg/workflow/threat_detection_conclude_script_test.go
index 110cd70dba2..3430422b3dc 100644
--- a/pkg/workflow/threat_detection_conclude_script_test.go
+++ b/pkg/workflow/threat_detection_conclude_script_test.go
@@ -112,7 +112,6 @@ func TestConcludeThreatDetectionScript_SkippedWhenRunDetectionFalse(t *testing.T
 	tmpDir := t.TempDir()
 	scriptPath := filepath.Join("..", "..", "actions", "setup", "sh", "conclude_threat_detection.sh")
 	outputFile := filepath.Join(tmpDir, "github_output.txt")
-	envFile := filepath.Join(tmpDir, "github_env.txt")
 	// No result file written — threat-detect is not installed — both should be irrelevant.
 	missingResult := filepath.Join(tmpDir, "missing_detection_result.json")
 
@@ -128,7 +127,6 @@ func TestConcludeThreatDetectionScript_SkippedWhenRunDetectionFalse(t *testing.T
 	cmd.Env = append(os.Environ(),
 		"RUN_DETECTION=false",
 		"GITHUB_OUTPUT="+outputFile,
-		"GITHUB_ENV="+envFile,
 		"PATH="+emptyBinDir+":"+os.Getenv("PATH"),
 	)
 
@@ -151,18 +149,6 @@ func TestConcludeThreatDetectionScript_SkippedWhenRunDetectionFalse(t *testing.T
 	if !strings.Contains(outputText, "reason=") {
 		t.Fatalf("expected reason= in GITHUB_OUTPUT, got: %s", outputText)
 	}
-
-	envData, err := os.ReadFile(envFile)
-	if err != nil {
-		t.Fatalf("failed to read GITHUB_ENV: %v", err)
-	}
-	envText := string(envData)
-	if !strings.Contains(envText, "GH_AW_DETECTION_CONCLUSION=skipped") {
-		t.Fatalf("expected GH_AW_DETECTION_CONCLUSION=skipped in GITHUB_ENV, got: %s", envText)
-	}
-	if !strings.Contains(envText, "GH_AW_DETECTION_REASON=") {
-		t.Fatalf("expected GH_AW_DETECTION_REASON= in GITHUB_ENV, got: %s", envText)
-	}
 }
 
 func TestConcludeThreatDetectionScript_InvokesThreatDetectConclude(t *testing.T) {

From 96321410970e8aa3118db20d5de58958a95fd7a6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 21 Jul 2026 12:34:30 +0000
Subject: [PATCH 5/8] fix: remove all GITHUB_ENV writes from
 conclude_threat_detection.sh

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 actions/setup/sh/conclude_threat_detection.sh |  2 --
 .../threat_detection_conclude_script_test.go  | 28 -------------------
 2 files changed, 30 deletions(-)

diff --git a/actions/setup/sh/conclude_threat_detection.sh b/actions/setup/sh/conclude_threat_detection.sh
index c4e685be41b..8920b5f665b 100755
--- a/actions/setup/sh/conclude_threat_detection.sh
+++ b/actions/setup/sh/conclude_threat_detection.sh
@@ -37,8 +37,6 @@ if [ ! -f "${RESULT_FILE}" ]; then
     echo "conclusion=warning" >> "${GITHUB_OUTPUT}"
     echo "success=false" >> "${GITHUB_OUTPUT}"
     echo "reason=agent_failure" >> "${GITHUB_OUTPUT}"
-    echo "GH_AW_DETECTION_CONCLUSION=warning" >> "${GITHUB_ENV}"
-    echo "GH_AW_DETECTION_REASON=agent_failure" >> "${GITHUB_ENV}"
     exit 0
   fi
   echo "ERR_SYSTEM: ❌ ${result_message}"
diff --git a/pkg/workflow/threat_detection_conclude_script_test.go b/pkg/workflow/threat_detection_conclude_script_test.go
index 3430422b3dc..a0dd06d70a4 100644
--- a/pkg/workflow/threat_detection_conclude_script_test.go
+++ b/pkg/workflow/threat_detection_conclude_script_test.go
@@ -13,7 +13,6 @@ const detectorStatusLine = "THREAT_DETECTION_STATUS: reason=engine_error exit=2"
 func TestConcludeThreatDetectionScript_MissingResultContinueOnError(t *testing.T) {
 	scriptPath := filepath.Join("..", "..", "actions", "setup", "sh", "conclude_threat_detection.sh")
 	outputFile := filepath.Join(t.TempDir(), "github_output.txt")
-	envFile := filepath.Join(t.TempDir(), "github_env.txt")
 	missingResult := filepath.Join(t.TempDir(), "missing_detection_result.json")
 
 	cmd := exec.Command("bash", scriptPath, missingResult)
@@ -22,7 +21,6 @@ func TestConcludeThreatDetectionScript_MissingResultContinueOnError(t *testing.T
 		"DETECTION_AGENTIC_EXECUTION_OUTCOME=failure",
 		"GH_AW_DETECTION_CONTINUE_ON_ERROR=TRUE",
 		"GITHUB_OUTPUT="+outputFile,
-		"GITHUB_ENV="+envFile,
 	)
 
 	out, err := cmd.CombinedOutput()
@@ -44,18 +42,6 @@ func TestConcludeThreatDetectionScript_MissingResultContinueOnError(t *testing.T
 	if !strings.Contains(outputText, "reason=agent_failure") {
 		t.Fatalf("expected reason=agent_failure in GITHUB_OUTPUT, got: %s", outputText)
 	}
-
-	envData, err := os.ReadFile(envFile)
-	if err != nil {
-		t.Fatalf("failed to read GITHUB_ENV: %v", err)
-	}
-	envText := string(envData)
-	if !strings.Contains(envText, "GH_AW_DETECTION_CONCLUSION=warning") {
-		t.Fatalf("expected warning conclusion in GITHUB_ENV, got: %s", envText)
-	}
-	if !strings.Contains(envText, "GH_AW_DETECTION_REASON=agent_failure") {
-		t.Fatalf("expected agent_failure reason in GITHUB_ENV, got: %s", envText)
-	}
 	if !strings.Contains(string(out), "continuing because GH_AW_DETECTION_CONTINUE_ON_ERROR=true") {
 		t.Fatalf("expected warning message about continue-on-error, got: %s", out)
 	}
@@ -65,7 +51,6 @@ func TestConcludeThreatDetectionScript_MissingResultSurfacesDetectorStatus(t *te
 	tempDir := t.TempDir()
 	scriptPath := filepath.Join("..", "..", "actions", "setup", "sh", "conclude_threat_detection.sh")
 	outputFile := filepath.Join(tempDir, "github_output.txt")
-	envFile := filepath.Join(tempDir, "github_env.txt")
 	missingResult := filepath.Join(tempDir, "missing_detection_result.json")
 	detectionLog := filepath.Join(tempDir, "detection.log")
 
@@ -80,7 +65,6 @@ func TestConcludeThreatDetectionScript_MissingResultSurfacesDetectorStatus(t *te
 		"GH_AW_DETECTION_CONTINUE_ON_ERROR=true",
 		"DETECTION_LOG_FILE="+detectionLog,
 		"GITHUB_OUTPUT="+outputFile,
-		"GITHUB_ENV="+envFile,
 	)
 
 	out, err := cmd.CombinedOutput()
@@ -94,18 +78,6 @@ func TestConcludeThreatDetectionScript_MissingResultSurfacesDetectorStatus(t *te
 	if !strings.Contains(string(out), "execution outcome: failure") {
 		t.Fatalf("expected warning output to include execution outcome, got: %s", out)
 	}
-
-	envData, err := os.ReadFile(envFile)
-	if err != nil {
-		t.Fatalf("failed to read GITHUB_ENV: %v", err)
-	}
-	envText := string(envData)
-	if !strings.Contains(envText, "GH_AW_DETECTION_CONCLUSION=warning") {
-		t.Fatalf("expected warning conclusion in GITHUB_ENV, got: %s", envText)
-	}
-	if !strings.Contains(envText, "GH_AW_DETECTION_REASON=agent_failure") {
-		t.Fatalf("expected agent_failure reason in GITHUB_ENV, got: %s", envText)
-	}
 }
 
 func TestConcludeThreatDetectionScript_SkippedWhenRunDetectionFalse(t *testing.T) {

From a2aff726b592b4fd4e8e47257de68c57689e370a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 21 Jul 2026 17:45:18 +0000
Subject: [PATCH 6/8] chore: recompile smoke-call-workflow to restore actions:
 read on call-smoke-workflow-call

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
---
 .github/workflows/smoke-call-workflow.lock.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/smoke-call-workflow.lock.yml b/.github/workflows/smoke-call-workflow.lock.yml
index b7fb052fab3..fbe4cdd2d92 100644
--- a/.github/workflows/smoke-call-workflow.lock.yml
+++ b/.github/workflows/smoke-call-workflow.lock.yml
@@ -1112,7 +1112,7 @@ jobs:
     # Imported from called workflow "smoke-workflow-call" because GitHub requires the caller job to grant permissions requested by reusable workflow jobs.
     # Review the called workflow's job-level permissions in ./.github/workflows/smoke-workflow-call.lock.yml.
     permissions:
-      actions: write
+      actions: read
       contents: read
       issues: write
       pull-requests: write

From 9f15eee988d7afafd8123132cf8a9b3f8cf8611f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 21 Jul 2026 18:59:01 +0000
Subject: [PATCH 7/8] test: add SkippedWhenRunDetectionUnset to cover the
 default guard behaviour

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
---
 .../threat_detection_conclude_script_test.go  | 48 +++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/pkg/workflow/threat_detection_conclude_script_test.go b/pkg/workflow/threat_detection_conclude_script_test.go
index a0dd06d70a4..d3274648150 100644
--- a/pkg/workflow/threat_detection_conclude_script_test.go
+++ b/pkg/workflow/threat_detection_conclude_script_test.go
@@ -123,6 +123,54 @@ func TestConcludeThreatDetectionScript_SkippedWhenRunDetectionFalse(t *testing.T
 	}
 }
 
+func TestConcludeThreatDetectionScript_SkippedWhenRunDetectionUnset(t *testing.T) {
+	tmpDir := t.TempDir()
+	scriptPath := filepath.Join("..", "..", "actions", "setup", "sh", "conclude_threat_detection.sh")
+	outputFile := filepath.Join(tmpDir, "github_output.txt")
+	missingResult := filepath.Join(tmpDir, "missing_detection_result.json")
+
+	emptyBinDir := filepath.Join(tmpDir, "empty-bin")
+	if err := os.MkdirAll(emptyBinDir, 0755); err != nil {
+		t.Fatalf("failed to create empty bin dir: %v", err)
+	}
+
+	// Build an environment that does NOT include RUN_DETECTION at all,
+	// verifying that the ${RUN_DETECTION:-false} default also triggers the guard.
+	filteredEnv := make([]string, 0, len(os.Environ()))
+	for _, e := range os.Environ() {
+		if !strings.HasPrefix(e, "RUN_DETECTION=") {
+			filteredEnv = append(filteredEnv, e)
+		}
+	}
+	filteredEnv = append(filteredEnv,
+		"GITHUB_OUTPUT="+outputFile,
+		"PATH="+emptyBinDir+":"+os.Getenv("PATH"),
+	)
+
+	cmd := exec.Command("bash", scriptPath, missingResult)
+	cmd.Env = filteredEnv
+
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("script should exit 0 when RUN_DETECTION is unset: %v\nOutput: %s", err, out)
+	}
+
+	outputData, err := os.ReadFile(outputFile)
+	if err != nil {
+		t.Fatalf("failed to read GITHUB_OUTPUT: %v", err)
+	}
+	outputText := string(outputData)
+	if !strings.Contains(outputText, "conclusion=skipped") {
+		t.Fatalf("expected conclusion=skipped in GITHUB_OUTPUT, got: %s", outputText)
+	}
+	if !strings.Contains(outputText, "success=true") {
+		t.Fatalf("expected success=true in GITHUB_OUTPUT, got: %s", outputText)
+	}
+	if !strings.Contains(outputText, "reason=") {
+		t.Fatalf("expected reason= in GITHUB_OUTPUT, got: %s", outputText)
+	}
+}
+
 func TestConcludeThreatDetectionScript_InvokesThreatDetectConclude(t *testing.T) {
 	tmpDir := t.TempDir()
 	scriptPath := filepath.Join("..", "..", "actions", "setup", "sh", "conclude_threat_detection.sh")

From aea69fc70d0d35e0304fa36595f0e4e3f7bc1ddd Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 22 Jul 2026 07:52:24 +0000
Subject: [PATCH 8/8] docs: remove stale GITHUB_ENV export claim from
 buildExternalDetectorConcludeStep comment

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 pkg/workflow/threat_detection_external.go | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/pkg/workflow/threat_detection_external.go b/pkg/workflow/threat_detection_external.go
index 7c4c8f32ca7..b313a2f4dbd 100644
--- a/pkg/workflow/threat_detection_external.go
+++ b/pkg/workflow/threat_detection_external.go
@@ -395,8 +395,9 @@ func (c *Compiler) buildUploadDetectionArtifactStep(data *WorkflowData) []string
 // buildExternalDetectorConcludeStep creates the conclude step for the external
 // threat-detect binary. It runs `threat-detect conclude --result-file ...` which reads
 // the structured detection_result.json and sets the detection_conclusion/detection_reason/
-// detection_success step outputs and exports GH_AW_DETECTION_CONCLUSION/GH_AW_DETECTION_REASON,
-// preserving the same gate contract as the inline parse_threat_detection_results.cjs path.
+// detection_success step outputs, preserving the same gate contract as the inline
+// parse_threat_detection_results.cjs path. Outputs (not env vars) are used exclusively;
+// downstream jobs consume these via needs.detection.outputs.* expressions.
 // The step ID (detection_conclusion) and env vars (RUN_DETECTION, DETECTION_AGENTIC_EXECUTION_OUTCOME,
 // GH_AW_DETECTION_CONTINUE_ON_ERROR) are byte-identical to the inline conclude step.
 func (c *Compiler) buildExternalDetectorConcludeStep(data *WorkflowData) []string {
