From d9c5b15e7734430ba73a8e43fe832f6ccb9ddddf Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Wed, 27 May 2026 08:34:38 -0700 Subject: [PATCH] test(brain): real PGLite round-trip E2E (matched-pair persistence) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test/skill-e2e-gbrain-roundtrip-local.test.ts (~145 LOC, periodic-tier, ~$0.001/run on Voyage): Real gbrain CLI round-trip against an isolated temp HOME: 1. gbrain init --pglite --embedding-model voyage:voyage-code-3 2. gbrain put office-hours/ --content 3. gbrain get 4. Assert every body line survives + title + tags + non-empty This is the matched-pair check for the v1.50.0.0 question "is the data we hope to save actually being saved?" — proves the gbrain CLI persistence contract gstack relies on, against a real engine. Does NOT involve the agent — pure CLI integration test. The agent obedience side is covered by the fake-CLI E2E in the prior commit. Skips cleanly when VOYAGE_API_KEY is unset OR gbrain CLI is missing from PATH, so CI without secrets degrades gracefully. Remote/Supabase routing is gbrain's contract — the same CLI shape works against every engine. gstack stops at local round-trip coverage to avoid re-testing gbrain's MCP client implementation. Co-Authored-By: Claude Opus 4.7 (1M context) --- test/skill-e2e-gbrain-roundtrip-local.test.ts | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 test/skill-e2e-gbrain-roundtrip-local.test.ts diff --git a/test/skill-e2e-gbrain-roundtrip-local.test.ts b/test/skill-e2e-gbrain-roundtrip-local.test.ts new file mode 100644 index 000000000..46e22b985 --- /dev/null +++ b/test/skill-e2e-gbrain-roundtrip-local.test.ts @@ -0,0 +1,162 @@ +/** + * E2E: real gbrain CLI round-trip against a local PGLite engine. + * + * Replaces the manual local probe documented in earlier drafts of + * docs/gbrain-write-surfaces.md. The matched-pair check the user asked + * for v1.50.0.0: "is the data we hope to save actually being saved?" + * + * What this proves: + * - The gbrain CLI subcommand shape gstack ships (`gbrain put + * --content ""`) actually persists to a + * real PGLite store. + * - The page is retrievable via `gbrain get ` with body + title + * intact (frontmatter is allowed to be reformatted by gbrain — we + * check semantic fields, not byte-exact YAML). + * - The `office-hours/` slug namespace works (no rejection, + * no auto-rewrite). + * + * What this does NOT prove (out of scope, owned elsewhere): + * - Agent obedience to the resolver instructions — that's the + * fake-CLI E2E (test/skill-e2e-office-hours-brain-writeback.test.ts). + * - Remote-MCP persistence — that's the write-shape E2E + * (test/skill-e2e-gbrain-roundtrip-remote.test.ts). + * - gbrain's own internal correctness — gbrain has its own test suite; + * this is a contract smoke test, not gbrain validation. + * + * Periodic tier. Real gbrain init + put triggers one Voyage embedding + * call (~$0.001/run). Skips when VOYAGE_API_KEY is unset OR gbrain is + * not on PATH, so CI without secrets degrades gracefully. + */ + +import { describe, test, expect, beforeAll, afterAll } from 'bun:test'; +import { execFileSync } from 'child_process'; +import { mkdtempSync, rmSync } from 'fs'; +import { tmpdir } from 'os'; +import { join } from 'path'; + +import { + describeIfSelected, + testConcurrentIfSelected, + runId, + createEvalCollector, +} from './helpers/e2e-helpers'; + +const evalCollector = createEvalCollector('e2e-gbrain-roundtrip-local'); + +function gbrainOnPath(): boolean { + try { + execFileSync('gbrain', ['--version'], { stdio: 'pipe', timeout: 5_000 }); + return true; + } catch { + return false; + } +} + +const SHOULD_RUN_GUARDS_OK = + gbrainOnPath() && !!process.env.VOYAGE_API_KEY; + +describeIfSelected( + 'GBrain local PGLite round-trip E2E', + ['gbrain-roundtrip-local'], + () => { + let tmpHome: string; + const slug = `office-hours/roundtrip-test-${Date.now()}`; + const body = `# Roundtrip test + +This is a deterministic round-trip test page used by the gstack v1.50.0.0 +brain-writeback verification. Generated at ${new Date().toISOString()}. + +If gbrain persisted this correctly, you should see this exact body when +you run \`gbrain get "${slug}"\`.`; + + beforeAll(() => { + if (!SHOULD_RUN_GUARDS_OK) { + // Will skip via testConcurrentIfSelected gate; nothing to set up. + tmpHome = ''; + return; + } + tmpHome = mkdtempSync(join(tmpdir(), 'gbrain-roundtrip-')); + + // Initialize a real PGLite gbrain in the isolated temp HOME. Explicit + // --embedding-model required because the local env has multiple + // providers ready (voyage + zeroentropyai); gbrain refuses to guess. + execFileSync( + 'gbrain', + ['init', '--pglite', '--embedding-model', 'voyage:voyage-code-3'], + { + env: { ...process.env, HOME: tmpHome }, + stdio: ['ignore', 'pipe', 'pipe'], + timeout: 60_000, + }, + ); + }); + + afterAll(() => { + if (tmpHome) { + try { + rmSync(tmpHome, { recursive: true, force: true }); + } catch { + // best effort + } + } + }); + + testConcurrentIfSelected( + 'gbrain-roundtrip-local', + async () => { + if (!SHOULD_RUN_GUARDS_OK) { + console.log( + '[skip] gbrain CLI not on PATH or VOYAGE_API_KEY unset; ' + + 'this E2E proves the gbrain CLI persistence contract gstack relies on. ' + + 'Run locally with `VOYAGE_API_KEY=... bun test ...` to verify before shipping.', + ); + return; + } + + const content = `--- +title: "Office Hours: Roundtrip Test" +tags: [design-doc, roundtrip-test] +--- +${body}`; + + // PUT the page. + execFileSync('gbrain', ['put', slug, '--content', content], { + env: { ...process.env, HOME: tmpHome }, + stdio: ['ignore', 'pipe', 'pipe'], + timeout: 30_000, + }); + + // GET it back. + const retrieved = execFileSync('gbrain', ['get', slug], { + env: { ...process.env, HOME: tmpHome }, + encoding: 'utf-8', + stdio: ['ignore', 'pipe', 'pipe'], + timeout: 10_000, + }); + + // The body MUST survive verbatim — every line of what we wrote + // must appear in what we got back. (Frontmatter reformatting is + // gbrain's prerogative; body text is data we own.) + for (const line of body.split('\n')) { + if (line.trim()) { + expect(retrieved).toContain(line); + } + } + + // Title is in the frontmatter — assert it's present (gbrain + // strips the constant prefix "title: " quote handling can vary). + expect(retrieved).toContain('Roundtrip Test'); + + // Tag survived. + expect(retrieved).toContain('design-doc'); + expect(retrieved).toContain('roundtrip-test'); + + // Sanity: the doc isn't empty or a 404 error. + expect(retrieved.length).toBeGreaterThan(body.length); + expect(retrieved).not.toContain('page_not_found'); + expect(retrieved).not.toContain('Page not found'); + }, + 120_000, + ); + }, +);