fix(setup-gbrain): warn about the ZeroEntropy sunset before Sept 4

ZeroEntropy was acquired by Notion and sunsets its hosted API on September 4, 2026. A gbrain configured with the zeroentropyai embedding recipe keeps importing pages after that date but embedding silently fails — pages land structurally with no semantic search, this repo's tracker P1 (TODOS.md NEXT PRIORITY). Nothing in gstack ever recommended ZeroEntropy (the dependency is gbrain-internal), so the gstack side is detection + advisory: the wireup helper warns when ~/.gbrain/config.json names the recipe (fail-open grep — a missing, unreadable, or other-provider config stays silent and never blocks a working setup), the setup-gbrain provider-default comments say never to select the legacy recipe for a new brain, and USING_GBRAIN_WITH_GSTACK.md gains a troubleshooting entry. The gbrain-side provider migration stays open upstream.

Refs #2365
This commit is contained in:
Garry Tan
2026-08-22 02:02:33 +00:00
parent 361dfebcbe
commit 8b426b3050
5 changed files with 61 additions and 0 deletions
+40
View File
@@ -341,6 +341,46 @@ describe('gstack-gbrain-source-wireup — wireup mode', () => {
});
});
describe('gstack-gbrain-source-wireup — ZeroEntropy sunset advisory (#2365)', () => {
// The hosted ZeroEntropy API dies Sept 4, 2026; a gbrain on the zeroentropyai
// recipe keeps importing but stops embedding SILENTLY. Detection is a
// fail-open grep of ~/.gbrain/config.json — missing/other-provider configs
// must stay silent and never block the wireup.
test('config naming zeroentropyai → sunset warning, wireup still succeeds', () => {
setupGstackRepo('git@github.com:user/gstack-brain-user.git');
makeFakeGbrain({});
fs.mkdirSync(path.join(tmpHome, '.gbrain'), { recursive: true });
fs.writeFileSync(
path.join(tmpHome, '.gbrain', 'config.json'),
JSON.stringify({ embedding: { recipe: 'zeroentropyai' } }),
);
const r = run([], { env: { GSTACK_BRAIN_NO_SYNC: '1' } });
expect(r.status).toBe(0);
expect(r.stderr).toContain('ZeroEntropy');
expect(r.stderr).toContain('2365');
});
test('config on another provider → no warning (fail-open, no false positive)', () => {
setupGstackRepo('git@github.com:user/gstack-brain-user.git');
makeFakeGbrain({});
fs.mkdirSync(path.join(tmpHome, '.gbrain'), { recursive: true });
fs.writeFileSync(
path.join(tmpHome, '.gbrain', 'config.json'),
JSON.stringify({ embedding: { recipe: 'voyage:voyage-code-3' } }),
);
const r = run([], { env: { GSTACK_BRAIN_NO_SYNC: '1' } });
expect(r.status).toBe(0);
expect(r.stderr).not.toContain('ZeroEntropy');
});
test('advisory docs entry exists (USING_GBRAIN_WITH_GSTACK.md content pin)', () => {
const doc = fs.readFileSync(path.join(ROOT, 'USING_GBRAIN_WITH_GSTACK.md'), 'utf-8');
expect(doc).toContain('September 4, 2026');
expect(doc).toContain('#2365');
});
});
describe('gstack-gbrain-source-wireup — --database-url lock (defends against external config rewrites)', () => {
test('--database-url flag is exported as GBRAIN_DATABASE_URL to child gbrain calls', () => {
setupGstackRepo('git@github.com:user/gstack-brain-user.git');