From 7808a1a3510e71ab83df29d512cff8a92d1c9b1d Mon Sep 17 00:00:00 2001 From: Gergo Magyar Date: Sun, 14 Jun 2026 09:04:25 +0000 Subject: [PATCH] fix(ci-setup): stop overselling the CI->server index delivery (P1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generated CI uploads .gitnexus/ as a workflow artifact, but nothing delivers it to the running server's persistent volume — yet GITNEXUS.md claimed the volume is "updated when the volume-sharing mechanism (rsync, artifact download, or live-mount) delivers a fresh index", naming three mechanisms the wizard never generates. A team following the doc verbatim gets a server serving an empty/stale index forever, with no loud failure. Replace that prose with an explicit "the wizard does not automate index delivery — it is a required operator step" statement plus a commented, target-matched, copy-adaptable example: for Docker, an on-server scheduled re-index (or `docker compose cp` of the downloaded artifact); for Azure Container App, `az storage file upload-batch` to the mounted file share. Co-Authored-By: Claude Opus 4.8 (1M context) --- gitnexus/src/cli/ci-setup/templates.ts | 40 ++++++++++++++++++- gitnexus/test/unit/ci-setup-templates.test.ts | 32 +++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/gitnexus/src/cli/ci-setup/templates.ts b/gitnexus/src/cli/ci-setup/templates.ts index 653b9fa6f..94072f944 100644 --- a/gitnexus/src/cli/ci-setup/templates.ts +++ b/gitnexus/src/cli/ci-setup/templates.ts @@ -410,6 +410,38 @@ Copy the MCP entry from \`.claude/gitnexus-mcp-snippet.json\` into \`~/.claude/s Replace \`\` with the server's IP or hostname.`; + const dockerDelivery = `**Docker:** the simplest option is to re-index on the server host directly, so the +\`gitnexus-data\` volume stays fresh without any artifact handoff: + +\`\`\`sh +# On the server, on a schedule (e.g. a cron entry): +# 0 * * * * cd /path/to/repo && npx gitnexus@latest analyze --skills +\`\`\` + +Or download the CI artifact and copy it into the running container's volume: + +\`\`\`sh +# gh run download --name "gitnexus-index-" --dir ./gitnexus-index +# docker compose cp ./gitnexus-index/. gitnexus:/data/gitnexus/ +\`\`\``; + + const acaDelivery = `**Azure Container App:** push the index to the Azure File share the app mounts: + +\`\`\`sh +# From a machine with ./.gitnexus and an \`az login\` session: +# az storage file upload-batch \\ +# --account-name "$STORAGE_ACCOUNT" \\ +# --destination "$FILE_SHARE" \\ +# --source ./.gitnexus +\`\`\``; + + const deliverySection = + opts.deploy === 'azure-container-app' + ? acaDelivery + : opts.deploy === 'both' + ? `${dockerDelivery}\n\n${acaDelivery}` + : dockerDelivery; + return `# GitNexus — Shared Code Intelligence Server GitNexus builds a knowledge graph of this repository and serves it as an MCP (Model Context Protocol) @@ -474,8 +506,12 @@ If the index is stale (CI hasn't run since the last push), Claude Code will stil on a slightly outdated graph. The staleness check step in the workflow fails the run if indexing produced no output, so stale-index PRs are blocked at CI. -For the shared server: the container reads the index from the persistent volume, which is updated -when the volume-sharing mechanism (rsync, artifact download, or live-mount) delivers a fresh index. +> **The wizard does not automate index delivery to the shared server.** CI uploads \`.gitnexus/\` as a +> workflow artifact; the running server reads its own persistent volume, and nothing connects the two +> automatically. Delivering the fresh index to the server's volume is a required operator step — pick +> the approach that matches your deployment (the commands below are commented; adapt paths/names): + +${deliverySection} --- diff --git a/gitnexus/test/unit/ci-setup-templates.test.ts b/gitnexus/test/unit/ci-setup-templates.test.ts index 0d20c1839..94d4dbe07 100644 --- a/gitnexus/test/unit/ci-setup-templates.test.ts +++ b/gitnexus/test/unit/ci-setup-templates.test.ts @@ -25,6 +25,38 @@ function makeOpts(overrides?: Partial): CiSetupOptions { }; } +function gitnexusMd(overrides?: Partial): string { + const files = generateFiles(makeOpts(overrides), DEFAULT_DETECT); + const md = files.find((f) => f.relativePath === 'GITNEXUS.md'); + if (!md) throw new Error('GITNEXUS.md not generated'); + return md.content; +} + +describe('GITNEXUS.md index delivery (U7)', () => { + it('does not oversell auto-delivery with a non-existent volume-sharing mechanism', () => { + const content = gitnexusMd(); + expect(content).not.toContain('volume-sharing mechanism'); + expect(content).toContain('does not automate index delivery'); + }); + + it('docker deploy shows an on-server delivery example (docker compose cp)', () => { + const content = gitnexusMd({ deploy: 'docker' }); + expect(content).toContain('docker compose cp'); + expect(content).not.toContain('az storage file upload-batch'); + }); + + it('ACA deploy shows an az storage file upload-batch example', () => { + const content = gitnexusMd({ deploy: 'azure-container-app' }); + expect(content).toContain('az storage file upload-batch'); + }); + + it('both deploy shows both delivery paths', () => { + const content = gitnexusMd({ deploy: 'both' }); + expect(content).toContain('docker compose cp'); + expect(content).toContain('az storage file upload-batch'); + }); +}); + describe('generateFiles', () => { describe('GitHub Actions workflow', () => { it('generates with correct port in healthcheck', () => {