mirror of
https://github.com/garrytan/gbrain.git
synced 2026-08-14 08:53:22 +00:00
* fix(onboard): resolve pack checks with file config
* test(onboard): sandbox GBRAIN_HOME in pre-existing pack-check tests
The fix routes checkPackUpgradeAvailable/checkTypeProliferation through
loadConfigFileOnly(), so the file's pre-existing tests now read the real
~/.gbrain/config.json and fail on any machine whose config sets
schema_pack. Wrap them in withEnv({ GBRAIN_HOME: emptyHome(), ... }),
matching the new test's idiom.
Co-authored-by: javieraldape <javieraldape@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: gbrain-contrib <gbrain-contrib@example.com>
Co-authored-by: Garry Tan <garrytan@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
gbrain-contrib
Garry Tan
parent
b6c75d802f
commit
3126b8fdfc
@@ -386,14 +386,15 @@ export async function checkPackUpgradeAvailable(
|
||||
): Promise<OnboardCheckResult> {
|
||||
try {
|
||||
const { loadActivePack, findPackSuccessors } = await import('../schema-pack/load-active.ts');
|
||||
const { loadConfigFileOnly } = await import('../config.ts');
|
||||
// Read the engine's DB-side schema_pack so a post-unify flip is visible
|
||||
// here even before the file-plane config catches up. Falls through to
|
||||
// file-plane/env/default resolution when unset.
|
||||
// here even before the file-plane config catches up. File-only config
|
||||
// preserves tier-6 schema_pack without merging transient env/database state.
|
||||
let dbConfig: string | undefined;
|
||||
try {
|
||||
dbConfig = (await engine.getConfig('schema_pack')) ?? undefined;
|
||||
} catch { /* engine.config may not exist on very old brains */ }
|
||||
const active = await loadActivePack({ cfg: null, remote: false, dbConfig })
|
||||
const active = await loadActivePack({ cfg: loadConfigFileOnly(), remote: false, dbConfig })
|
||||
.catch(() => null);
|
||||
if (!active) {
|
||||
return {
|
||||
@@ -463,11 +464,12 @@ export async function checkTypeProliferation(
|
||||
let declared = 15; // fallback to gbrain-base-v2 default if pack unavailable
|
||||
try {
|
||||
const { loadActivePack } = await import('../schema-pack/load-active.ts');
|
||||
const { loadConfigFileOnly } = await import('../config.ts');
|
||||
let dbConfig: string | undefined;
|
||||
try {
|
||||
dbConfig = (await engine.getConfig('schema_pack')) ?? undefined;
|
||||
} catch { /* tolerate pre-config brains */ }
|
||||
const active = await loadActivePack({ cfg: null, remote: false, dbConfig })
|
||||
const active = await loadActivePack({ cfg: loadConfigFileOnly(), remote: false, dbConfig })
|
||||
.catch(() => null);
|
||||
if (active) declared = active.manifest.page_types.length;
|
||||
} catch {
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
// JOIN (F12); manual_only RemediationStep flag round-trips through render.
|
||||
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'bun:test';
|
||||
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { PGLiteEngine } from '../src/core/pglite-engine.ts';
|
||||
import { resetPgliteState } from './helpers/reset-pglite.ts';
|
||||
import { emptyHome, withEnv } from './helpers/with-env.ts';
|
||||
import {
|
||||
checkPackUpgradeAvailable,
|
||||
checkTypeProliferation,
|
||||
@@ -56,29 +60,57 @@ describe('checkPackUpgradeAvailable', () => {
|
||||
it('fires on gbrain-base brain with gbrain-base-v2 available', async () => {
|
||||
// Default active pack is gbrain-base; gbrain-base-v2 declares
|
||||
// migration_from: {pack: gbrain-base, version: "1.x"}.
|
||||
const result = await checkPackUpgradeAvailable(engine);
|
||||
expect(result.check.name).toBe('pack_upgrade_available');
|
||||
expect(result.check.status).toBe('warn');
|
||||
expect(result.check.message).toContain('gbrain-base-v2');
|
||||
expect(result.remediations.length).toBe(1);
|
||||
expect(result.remediations[0].job).toBe('unify-types');
|
||||
expect(result.remediations[0].protected).toBe(true);
|
||||
expect(result.remediations[0].params.target_pack).toBe('gbrain-base-v2');
|
||||
// Sandbox GBRAIN_HOME: the check reads file-plane config, so a dev
|
||||
// machine whose real ~/.gbrain/config.json sets schema_pack would
|
||||
// flip this assertion.
|
||||
await withEnv({ GBRAIN_HOME: emptyHome(), GBRAIN_SCHEMA_PACK: undefined }, async () => {
|
||||
const result = await checkPackUpgradeAvailable(engine);
|
||||
expect(result.check.name).toBe('pack_upgrade_available');
|
||||
expect(result.check.status).toBe('warn');
|
||||
expect(result.check.message).toContain('gbrain-base-v2');
|
||||
expect(result.remediations.length).toBe(1);
|
||||
expect(result.remediations[0].job).toBe('unify-types');
|
||||
expect(result.remediations[0].protected).toBe(true);
|
||||
expect(result.remediations[0].params.target_pack).toBe('gbrain-base-v2');
|
||||
});
|
||||
});
|
||||
|
||||
it('honors file-plane schema_pack when DB config is unset', async () => {
|
||||
const home = mkdtempSync(join(tmpdir(), 'gbrain-pack-upgrade-'));
|
||||
const configDir = join(home, '.gbrain');
|
||||
mkdirSync(configDir, { recursive: true });
|
||||
writeFileSync(
|
||||
join(configDir, 'config.json'),
|
||||
JSON.stringify({ schema_pack: 'gbrain-base-v2' }, null, 2),
|
||||
);
|
||||
|
||||
await withEnv({ GBRAIN_HOME: home, GBRAIN_SCHEMA_PACK: undefined }, async () => {
|
||||
_resetPackCacheForTests();
|
||||
const result = await checkPackUpgradeAvailable(engine);
|
||||
expect(result.check.name).toBe('pack_upgrade_available');
|
||||
expect(result.check.status).toBe('ok');
|
||||
expect(result.check.message).toContain('gbrain-base-v2');
|
||||
expect(result.remediations).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('manual_only routing via render.ts allowlist (D17)', async () => {
|
||||
const result = await checkPackUpgradeAvailable(engine);
|
||||
const step = result.remediations[0];
|
||||
const rec = toOnboardRecommendation(step);
|
||||
expect(rec.apply_policy).toBe('manual_only');
|
||||
await withEnv({ GBRAIN_HOME: emptyHome(), GBRAIN_SCHEMA_PACK: undefined }, async () => {
|
||||
const result = await checkPackUpgradeAvailable(engine);
|
||||
const step = result.remediations[0];
|
||||
const rec = toOnboardRecommendation(step);
|
||||
expect(rec.apply_policy).toBe('manual_only');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkTypeProliferation (D16 pack-aware ratio)', () => {
|
||||
it('returns ok when distinct types under declared+5 threshold', async () => {
|
||||
await seedPages(['note', 'meeting', 'slack']);
|
||||
const result = await checkTypeProliferation(engine);
|
||||
expect(result.check.status).toBe('ok');
|
||||
await withEnv({ GBRAIN_HOME: emptyHome(), GBRAIN_SCHEMA_PACK: undefined }, async () => {
|
||||
const result = await checkTypeProliferation(engine);
|
||||
expect(result.check.status).toBe('ok');
|
||||
});
|
||||
});
|
||||
|
||||
it('warns when distinct types exceed declared+5', async () => {
|
||||
@@ -86,17 +118,19 @@ describe('checkTypeProliferation (D16 pack-aware ratio)', () => {
|
||||
// the same way checkTypeProliferation does, then seed declared+6 so the
|
||||
// test keeps passing when the base pack grows (e.g. #2390 added
|
||||
// event + diary and silently moved the fixed threshold).
|
||||
const { loadActivePack } = await import('../src/core/schema-pack/load-active.ts');
|
||||
const dbConfig = (await engine.getConfig('schema_pack')) ?? undefined;
|
||||
const active = await loadActivePack({ cfg: null, remote: false, dbConfig }).catch(() => null);
|
||||
const declared = active ? active.manifest.page_types.length : 15;
|
||||
const seedCount = declared + 6; // one past the warn threshold (declared+5)
|
||||
const types: string[] = [];
|
||||
for (let i = 0; i < seedCount; i++) types.push(`custom-type-${i}`);
|
||||
await seedPages(types);
|
||||
const result = await checkTypeProliferation(engine);
|
||||
expect(result.check.status).toBe('warn');
|
||||
expect(result.check.message).toMatch(new RegExp(`${seedCount} distinct`));
|
||||
await withEnv({ GBRAIN_HOME: emptyHome(), GBRAIN_SCHEMA_PACK: undefined }, async () => {
|
||||
const { loadActivePack } = await import('../src/core/schema-pack/load-active.ts');
|
||||
const dbConfig = (await engine.getConfig('schema_pack')) ?? undefined;
|
||||
const active = await loadActivePack({ cfg: null, remote: false, dbConfig }).catch(() => null);
|
||||
const declared = active ? active.manifest.page_types.length : 15;
|
||||
const seedCount = declared + 6; // one past the warn threshold (declared+5)
|
||||
const types: string[] = [];
|
||||
for (let i = 0; i < seedCount; i++) types.push(`custom-type-${i}`);
|
||||
await seedPages(types);
|
||||
const result = await checkTypeProliferation(engine);
|
||||
expect(result.check.status).toBe('warn');
|
||||
expect(result.check.message).toMatch(new RegExp(`${seedCount} distinct`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user