From d38fb3159f36e22d1ecb671205c6681a9844d386 Mon Sep 17 00:00:00 2001 From: Prekshi Vyas Date: Fri, 24 Jul 2026 20:18:43 -0700 Subject: [PATCH 1/5] fix(ci): select DCode E2E for runtime changes Signed-off-by: Prekshi Vyas --- test/e2e/README.md | 12 ++++++++---- test/pr-e2e-gate-fork-skip.test.ts | 5 +++-- test/pr-risk-plan.test.ts | 27 ++++++++++++++++++++++++++- tools/advisors/risk-plan.mts | 20 ++++++++++++++------ 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/test/e2e/README.md b/test/e2e/README.md index 9c6cc982782..d6da785f6e2 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -454,10 +454,14 @@ through cold onboarding and a real first turn. The repository-root `Dockerfile.base` remains in only the `platform-install` family. It selects `cloud-onboard` and does not trigger the cold `full-e2e` path. -The Deep Agents Code headless-inference check additionally selects the exact -`ubuntu-repo-cloud-langchain-deepagents-code` typed target. That target is -hashed into the risk plan beside the control-plane floor jobs, so the -controller dispatches both selector types in one correlated workflow run. +Non-documentation runtime changes under `agents/langchain-deepagents-code/` +and changes to the Deep Agents Code headless-inference check select the exact +`ubuntu-repo-cloud-langchain-deepagents-code` typed target. Documentation and +ordinary test changes alone do not select it. The target is hashed into the +risk plan beside any control-plane floor jobs, so the controller dispatches +both selector types in one correlated workflow run. Fork revisions instead +require the explicit credentialed-E2E skip approval and cannot pass through an +empty plan. An internal revision whose matched control-plane files are drawn only from the trusted controller and observer boundaries—`.github/workflows/pr-e2e-gate.yaml`, `tools/e2e/pr-e2e-gate.mts`, and `tools/e2e/pr-e2e-required.mts`—automatically diff --git a/test/pr-e2e-gate-fork-skip.test.ts b/test/pr-e2e-gate-fork-skip.test.ts index 035be950c08..9968f5ccd6e 100644 --- a/test/pr-e2e-gate-fork-skip.test.ts +++ b/test/pr-e2e-gate-fork-skip.test.ts @@ -29,6 +29,7 @@ const CI_RUN_ID = 99; const CI_RUN_ATTEMPT = 3; const GATE_RUN_ID = 77; const APPROVAL_RUN_ID = 123; +const DCODE_PATCH = "agents/langchain-deepagents-code/patch-managed-deepagents-code.py"; afterEach(() => { vi.restoreAllMocks(); vi.unstubAllEnvs(); @@ -278,7 +279,7 @@ function successfulApprovedForkRoutes(approvals: unknown) { } describe("PR E2E controller fork credentialed E2E skip approval safety", () => { - it("plans a risky fork without dispatching secret-bearing E2E", async () => { + it("requires the selected target and skip approval before a DCode runtime fork can pass E2E (#7463)", async () => { const workDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-pr-e2e-gate-fork-")); const outputPath = path.join(workDir, "github-output"); fs.writeFileSync(outputPath, "", { mode: 0o600 }); @@ -304,7 +305,7 @@ describe("PR E2E controller fork credentialed E2E skip approval safety", () => { ), githubFetchRoute( ({ url }) => url.includes("/pulls/42/files?"), - () => githubResponse([{ filename: "src/lib/onboard.ts" }]), + () => githubResponse([{ filename: DCODE_PATCH }]), ), githubFetchRoute( ({ url, method }) => url.endsWith("/check-runs/17") && method === "PATCH", diff --git a/test/pr-risk-plan.test.ts b/test/pr-risk-plan.test.ts index 1cc6e672114..d73b5f32523 100644 --- a/test/pr-risk-plan.test.ts +++ b/test/pr-risk-plan.test.ts @@ -28,7 +28,7 @@ describe("deterministic PR risk plan", () => { const second = plan("src/lib/onboard.ts", "src/lib/state/registry.ts"); expect(first).toEqual(second); - expect(first.version).toBe(5); + expect(first.version).toBe(6); expect(first.headSha).toBe(HEAD_SHA); expect(first.planHash).toMatch(/^[a-f0-9]{64}$/u); expect(first.changedFiles).toEqual(["src/lib/onboard.ts", "src/lib/state/registry.ts"]); @@ -115,6 +115,31 @@ describe("deterministic PR risk plan", () => { expect(requiresCredentialedE2eAuthorization(result)).toBe(true); }); + it("selects the Deep Agents Code target for its managed runtime changes (#7463)", () => { + const changedFiles = [ + "agents/langchain-deepagents-code/dependency-review.md", + "agents/langchain-deepagents-code/patch-managed-deepagents-code.py", + "test/langchain-deepagents-code-managed-model-params.test.ts", + "test/langchain-deepagents-code-nemotron-profile-plugin.test.ts", + ]; + const result = buildRiskPlan({ headSha: HEAD_SHA, changedFiles }); + const docsAndTestsOnly = plan( + "agents/langchain-deepagents-code/dependency-review.md", + "test/langchain-deepagents-code-managed-model-params.test.ts", + ); + + expect(riskPlanRequiredTargetIds(result)).toEqual(PR_E2E_TYPED_TARGET_IDS); + expect(result.requiredTargets).toEqual([ + expect.objectContaining({ + id: PR_E2E_TYPED_TARGET_IDS[0], + families: ["focused-e2e"], + matchedFiles: ["agents/langchain-deepagents-code/patch-managed-deepagents-code.py"], + }), + ]); + expect(result.tier).toBe(2); + expect(riskPlanRequiredTargetIds(docsAndTestsOnly)).toEqual([]); + }); + it("does not infer security or inference risk from unrelated path substrings", () => { const result = plan("src/lib/actions/sandbox/mcp-bridge-provider.ts", "src/lib/secretary.ts"); diff --git a/tools/advisors/risk-plan.mts b/tools/advisors/risk-plan.mts index 169d325ebe4..f807fcc5c26 100644 --- a/tools/advisors/risk-plan.mts +++ b/tools/advisors/risk-plan.mts @@ -3,13 +3,14 @@ import { createHash } from "node:crypto"; -export const RISK_PLAN_VERSION = 5 as const; +export const RISK_PLAN_VERSION = 6 as const; export const PR_E2E_TYPED_TARGET_IDS = ["ubuntu-repo-cloud-langchain-deepagents-code"] as const; const PR_E2E_TYPED_TARGET_ID_SET = new Set(PR_E2E_TYPED_TARGET_IDS); const DEEPAGENTS_HEADLESS_INFERENCE_CHECK = "test/e2e/e2e-cloud-experimental/checks/07-deepagents-code-headless-inference.sh"; +const DEEPAGENTS_CODE_RUNTIME_ROOT = "agents/langchain-deepagents-code/"; export type RiskTier = 0 | 1 | 2 | 3; export type RiskFamilyId = @@ -108,10 +109,10 @@ const RISK_RELEVANT_TEST_FILES = new Set([ "test/e2e/risk-signal-reporter.ts", ]); const FOCUSED_E2E_SUMMARY = - "Changed workflow-wired E2E tests must execute through their trusted canonical jobs or typed targets."; + "Changed runtime surfaces and workflow-wired E2E tests must execute through their trusted canonical jobs or typed targets."; const FOCUSED_E2E_INVARIANTS = [ - "the changed test remains wired to a job or typed-target selector declared by the trusted workflow", - "the canonical execution path runs the changed test rather than treating it as advisory coverage", + "the selected job or typed target exercises the changed runtime surface or test", + "the canonical execution path runs the required coverage rather than treating it as advisory", ] as const; export function isPrE2eTypedTargetId(value: string): boolean { @@ -121,11 +122,18 @@ export function isPrE2eTypedTargetId(value: string): boolean { export function focusedPrE2eTargetsForChangedFiles( changedFiles: readonly string[], ): TrustedFocusedE2eTarget[] { - return changedFiles.includes(DEEPAGENTS_HEADLESS_INFERENCE_CHECK) + const matchedFiles = stableUnique( + changedFiles.filter( + (file) => + file === DEEPAGENTS_HEADLESS_INFERENCE_CHECK || + (file.startsWith(DEEPAGENTS_CODE_RUNTIME_ROOT) && !/\.(?:md|mdx)$/u.test(file)), + ), + ); + return matchedFiles.length > 0 ? [ { id: PR_E2E_TYPED_TARGET_IDS[0], - matchedFiles: [DEEPAGENTS_HEADLESS_INFERENCE_CHECK], + matchedFiles, }, ] : []; From 9dd1c973c61c6dd2959c880489635fe015994107 Mon Sep 17 00:00:00 2001 From: Prekshi Vyas Date: Fri, 24 Jul 2026 20:32:02 -0700 Subject: [PATCH 2/5] test(ci): cover DCode selector exclusions Signed-off-by: Prekshi Vyas --- test/e2e/README.md | 7 ++++--- test/pr-risk-plan.test.ts | 2 ++ tools/advisors/risk-plan.mts | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/test/e2e/README.md b/test/e2e/README.md index d6da785f6e2..e6ca0819da6 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -459,9 +459,10 @@ and changes to the Deep Agents Code headless-inference check select the exact `ubuntu-repo-cloud-langchain-deepagents-code` typed target. Documentation and ordinary test changes alone do not select it. The target is hashed into the risk plan beside any control-plane floor jobs, so the controller dispatches -both selector types in one correlated workflow run. Fork revisions instead -require the explicit credentialed-E2E skip approval and cannot pass through an -empty plan. +both selector types in one correlated workflow run. Fork revisions whose plans +select credential-bearing jobs or targets instead require explicit +credentialed-E2E skip approval. Plans with no selected jobs or targets can +complete without an E2E run. An internal revision whose matched control-plane files are drawn only from the trusted controller and observer boundaries—`.github/workflows/pr-e2e-gate.yaml`, `tools/e2e/pr-e2e-gate.mts`, and `tools/e2e/pr-e2e-required.mts`—automatically diff --git a/test/pr-risk-plan.test.ts b/test/pr-risk-plan.test.ts index d73b5f32523..97d55e18400 100644 --- a/test/pr-risk-plan.test.ts +++ b/test/pr-risk-plan.test.ts @@ -125,6 +125,8 @@ describe("deterministic PR risk plan", () => { const result = buildRiskPlan({ headSha: HEAD_SHA, changedFiles }); const docsAndTestsOnly = plan( "agents/langchain-deepagents-code/dependency-review.md", + "agents/langchain-deepagents-code/runtime-notes.mdx", + "agents/langchain-deepagents-code/resolver.test.ts", "test/langchain-deepagents-code-managed-model-params.test.ts", ); diff --git a/tools/advisors/risk-plan.mts b/tools/advisors/risk-plan.mts index f807fcc5c26..6890e5ea8d0 100644 --- a/tools/advisors/risk-plan.mts +++ b/tools/advisors/risk-plan.mts @@ -126,7 +126,7 @@ export function focusedPrE2eTargetsForChangedFiles( changedFiles.filter( (file) => file === DEEPAGENTS_HEADLESS_INFERENCE_CHECK || - (file.startsWith(DEEPAGENTS_CODE_RUNTIME_ROOT) && !/\.(?:md|mdx)$/u.test(file)), + (file.startsWith(DEEPAGENTS_CODE_RUNTIME_ROOT) && isRuntimeRelevant(file)), ), ); return matchedFiles.length > 0 From 6373d3db4e7985befa1697c98c73d7107faf20d8 Mon Sep 17 00:00:00 2001 From: Prekshi Vyas Date: Sun, 26 Jul 2026 10:35:46 -0700 Subject: [PATCH 3/5] test(ci): accept target-only fork approval plans Signed-off-by: Prekshi Vyas --- test/pr-e2e-gate-fork-approval.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pr-e2e-gate-fork-approval.test.ts b/test/pr-e2e-gate-fork-approval.test.ts index 5fb17a09116..a840c89cfa8 100644 --- a/test/pr-e2e-gate-fork-approval.test.ts +++ b/test/pr-e2e-gate-fork-approval.test.ts @@ -389,7 +389,7 @@ describe("PR E2E controller fork credentialed E2E approval safety", () => { expect(JSON.stringify(pending?.body)).toContain("head repository `contributor/NemoClaw`"); expect(JSON.stringify(pending?.body)).toContain(`head SHA \`${HEAD_SHA}\``); expect(JSON.stringify(pending?.body)).toContain(`base SHA \`${BASE_SHA}\``); - expect(JSON.stringify(pending?.body)).toContain("jobs:"); + expect(JSON.stringify(pending?.body)).toContain("targets:"); expect(JSON.stringify(pending?.body)).toContain("deterministic plan"); expect(fs.readFileSync(outputPath, "utf8")).toContain( [ From 7f1af4d74a8dd8fb912a9ca6f059ea2945378203 Mon Sep 17 00:00:00 2001 From: Prekshi Vyas Date: Sun, 26 Jul 2026 11:03:26 -0700 Subject: [PATCH 4/5] fix(hermes): refresh published base image Signed-off-by: Prekshi Vyas --- agents/hermes/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agents/hermes/Dockerfile b/agents/hermes/Dockerfile index a07734cf40b..eb0b0a0d719 100644 --- a/agents/hermes/Dockerfile +++ b/agents/hermes/Dockerfile @@ -6,7 +6,7 @@ # Layers PR-specific code (plugin, config, startup script) on top of the # pre-built Hermes base image. Mirrors the OpenClaw Dockerfile structure. -ARG BASE_IMAGE=ghcr.io/nvidia/nemoclaw/hermes-sandbox-base@sha256:fa05221f5c7bcafea7e263c84e5d06f87e37d1ccb78dc28c113f1a4066aa544c +ARG BASE_IMAGE=ghcr.io/nvidia/nemoclaw/hermes-sandbox-base@sha256:c925afe7c0742474166a4813a59f5961a93da4d130e9b35fb04088a384702142 # Group repository-owned files outside the final image so BuildKit can collapse # related files without invalidating earlier final-image work. From 13efac6d67a133bb2b4395d14e5c0b6dd534c419 Mon Sep 17 00:00:00 2001 From: Prekshi Vyas Date: Sun, 26 Jul 2026 11:33:44 -0700 Subject: [PATCH 5/5] docs(ci): describe protected fork E2E approval Signed-off-by: Prekshi Vyas --- test/e2e/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/README.md b/test/e2e/README.md index de8dbce7289..8dcb554d175 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -544,9 +544,9 @@ and changes to the Deep Agents Code headless-inference check select the exact ordinary test changes alone do not select it. The target is hashed into the risk plan beside any control-plane floor jobs, so the controller dispatches both selector types in one correlated workflow run. Fork revisions whose plans -select credential-bearing jobs or targets instead require explicit -credentialed-E2E skip approval. Plans with no selected jobs or targets can -complete without an E2E run. +select credential-bearing jobs or targets instead require explicit protected +credentialed-E2E approval. Plans with no selected jobs or targets can complete +without an E2E run. An internal revision whose matched control-plane files are drawn only from the trusted controller and observer boundaries—`.github/workflows/pr-e2e-gate.yaml`, `tools/e2e/pr-e2e-gate.mts`, and `tools/e2e/pr-e2e-required.mts`—automatically