From 2ea00a2b22c65073c77148d6f8303e0e31612851 Mon Sep 17 00:00:00 2001 From: Abhigyan Patwari <126312502+abhigyanpatwari@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:26:54 +0530 Subject: [PATCH] fix(ci): install root and shared node_modules for the evolution benchmark (#2575) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(ci): install root and shared node_modules for the evolution benchmark The first real workflow_dispatch of the skill-evolution loop failed at task binding: capture_task_dependency_binding aborted with SandboxError: sandbox_copy path is unavailable: node_modules: No such file or directory The benchmark tasks sandbox-copy node_modules from three locations (tasks.scenarios.yaml) — the monorepo root, gitnexus-shared, and gitnexus — mirroring a full dev checkout. The install step only ran `npm ci` in gitnexus/, so the root and gitnexus-shared node_modules never existed and the loop died before any agent ran. Install all three (root, then build gitnexus-shared, then build gitnexus), matching the per-package install in ci-tests.yml plus the root deps the tasks require. A new contract test pins all three installs so this fails in CI rather than on the next real run — the same guard the workflow's other two P1 fixes got. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ * fix(ci): only add the missing root install; the subpackage steps already exist The initial fix redundantly rebuilt gitnexus-shared and gitnexus inside the gitnexus step — but the workflow already builds both in their own dedicated steps. Only the monorepo root node_modules was missing. Add a single "Install monorepo root dependencies" step and leave the two subpackage build steps untouched, so the benchmark's root sandbox_copy resolves without double-building. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Va5uu9Ar3e45QZ5xFsG4AZ --------- Co-authored-by: Gergo Magyar Co-authored-by: Claude Opus 4.8 --- .github/workflows/gitnexus-skill-evolution.yml | 11 +++++++++++ .../test/unit/skill-evolution-workflow.test.ts | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/.github/workflows/gitnexus-skill-evolution.yml b/.github/workflows/gitnexus-skill-evolution.yml index 936b46a92..66e87ad18 100644 --- a/.github/workflows/gitnexus-skill-evolution.yml +++ b/.github/workflows/gitnexus-skill-evolution.yml @@ -151,6 +151,17 @@ jobs: test "$("${canary_runtime}/node_modules/@anthropic-ai/claude-code-linux-x64/claude" --version)" = \ '2.1.214 (Claude Code)' + - name: Install monorepo root dependencies + run: | + set -euo pipefail + # The benchmark's task bindings sandbox-copy node_modules from the + # monorepo root as well as gitnexus-shared and gitnexus (see the + # sandbox_copy entries in tasks.scenarios.yaml). The two steps below + # install the subpackage trees; the root tree needs its own install + # or capture_task_dependency_binding aborts at task binding on the + # missing root node_modules. + npm ci + - name: Build pinned shared runtime run: | set -euo pipefail diff --git a/gitnexus/test/unit/skill-evolution-workflow.test.ts b/gitnexus/test/unit/skill-evolution-workflow.test.ts index 50b93ec02..c2c3240fe 100644 --- a/gitnexus/test/unit/skill-evolution-workflow.test.ts +++ b/gitnexus/test/unit/skill-evolution-workflow.test.ts @@ -59,6 +59,20 @@ describe('gitnexus skill-evolution workflow contract', () => { expect(provision).toContain('${HOME}/GitNexus'); }); + it('installs node_modules for the monorepo root, gitnexus-shared, and gitnexus', () => { + // The benchmark sandbox-copies node_modules from all three (tasks.scenarios.yaml). + // The root tree was absent on the first real run because only the two subpackage + // steps ran, so capture_task_dependency_binding aborted at task binding. + const rootStep = evolveJob?.steps?.find( + ({ name }) => name === 'Install monorepo root dependencies', + ); + expect(rootStep).toBeDefined(); + expect(rootStep).not.toHaveProperty('working-directory'); // installs at the repo root + expect(String(rootStep?.run)).toContain('npm ci'); + expect(stepRun('Build pinned shared runtime')).toContain('npm ci'); + expect(stepRun('Install and build pinned GitNexus runtime')).toContain('npm ci'); + }); + it('names the promotion branch with the run attempt for re-run recovery', () => { const openPr = stepRun('Open the promotion PR'); expect(openPr).toContain('${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}');