mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
* fix(reindex): add-only tag reconciliation + DB-only re-chunk preserves frontmatter (#1621) reindex --markdown and re-import no longer wipe DB-side enrichment tags. Tag reconciliation is now ADD-ONLY (import-file.ts): re-import adds current frontmatter tags and never deletes, so auto/dream/signal-detector tags survive. The reindex DB-only fallback reconstructs full markdown via serializeMarkdown so re-chunking a page with no on-disk source preserves frontmatter/title/timeline. * fix(migrations): v0.13.1 grandfather chunked, source-safe, soft-delete-filtered (#1581) phaseCGrandfather rewritten from a per-page getPage+putPage loop (which hung 70+ min on an 82K-page PGLite brain) to a chunked bulk SQL pass keyed on pages.id (NOT slug — slug isn't globally unique), filtering deleted_at IS NULL, with a batched rollback log carrying source identity. * fix(migrations): run schema phases in-process to fix Windows getaddrinfo ENOTFOUND (#1605) The 9 'gbrain init --migrate-only' execSync spawns died on Windows+bun+Supabase (child DNS resolution). runMigrateOnlyCore (extracted from initMigrateOnly) runs the schema bring-up in-process for all engines, unblocking schema_version advancement. Includes async-call-site audit, a wall-clock guard, and a runGbrainSubprocess stderr-capture wrapper for the remaining backfill spawns. * fix(sync): ReDoS hardening + diagnostics for schema-pack regexes (#1569) Input-length cap in runRegexBounded + route the unbounded link-inference path through it (closes the only no-timeout ReDoS hole); star-height lint rule warns on nested-quantifier patterns; --no-schema-pack sync escape hatch; GBRAIN_SYNC_TRACE per-file begin heartbeat; PGLite serve/sync concurrency doc. Defensive hardening + diagnostics — the deterministic ~3100-file wedge root cause remains open (no repro). * docs(todos): file v0.41.37.0 fix-wave follow-ups (#1621/#1605/#1569) * chore: bump version and changelog (v0.41.37.0) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: sync README + CLAUDE.md for v0.41.37.0 critical fix wave Add reindex add-only tag reconciliation (#1621), v0.13.1 grandfather + Windows in-process migration (#1581/#1605), and schema-pack ReDoS hardening + sync --no-schema-pack / GBRAIN_SYNC_TRACE triage (#1569) to CLAUDE.md key-files annotations and README Troubleshooting. Regenerated llms-full.txt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ci): bump llms-full.txt budget 700KB→750KB (CLAUDE.md crossed 700KB after master merge) The build-llms size-budget test failed: llms-full.txt is 703,244 bytes after the v0.41.37.0 key-files annotations merged on top of master's v0.41.34/35/36 CLAUDE.md additions. Matches the v0.41.9.0 precedent (600→700); the single-fetch bundle still fits comfortably in modern long-context models. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
99 lines
4.0 KiB
TypeScript
99 lines
4.0 KiB
TypeScript
/**
|
|
* Unit tests for v0.16.0 migration orchestrator + registry.
|
|
*
|
|
* The full schema verification lives in E2E (Postgres). These unit tests
|
|
* cover:
|
|
* - registry wiring (v0.16.0 registered + lookup works)
|
|
* - v0.14.0 noop stub wired (gapless version sequence)
|
|
* - migration metadata (version, pitch)
|
|
* - dry-run short-circuits both phases
|
|
* - required table names constant
|
|
*/
|
|
|
|
import { describe, test, expect } from 'bun:test';
|
|
import { migrations, getMigration } from '../src/commands/migrations/index.ts';
|
|
import { __testing } from '../src/commands/migrations/v0_16_0.ts';
|
|
|
|
describe('v0.16.0 migration', () => {
|
|
test('is registered in the migrations registry', () => {
|
|
const v0_16_0 = getMigration('0.16.0');
|
|
expect(v0_16_0).not.toBeNull();
|
|
expect(v0_16_0?.version).toBe('0.16.0');
|
|
});
|
|
|
|
test('v0.14.0 noop stub is registered (gapless sequence)', () => {
|
|
const v0_14_0 = getMigration('0.14.0');
|
|
expect(v0_14_0).not.toBeNull();
|
|
expect(v0_14_0?.version).toBe('0.14.0');
|
|
});
|
|
|
|
test('migrations array has no version gaps through 0.16.0', () => {
|
|
const versions = migrations.map(m => m.version);
|
|
expect(versions).toContain('0.13.1');
|
|
expect(versions).toContain('0.14.0');
|
|
expect(versions).toContain('0.16.0');
|
|
// order check — registry is semver-sorted in the source
|
|
const v15Idx = versions.indexOf('0.16.0');
|
|
const v14Idx = versions.indexOf('0.14.0');
|
|
const v131Idx = versions.indexOf('0.13.1');
|
|
expect(v131Idx).toBeLessThan(v14Idx);
|
|
expect(v14Idx).toBeLessThan(v15Idx);
|
|
});
|
|
|
|
test('feature pitch has headline and description', () => {
|
|
const m = getMigration('0.16.0');
|
|
expect(m?.featurePitch.headline).toBeTruthy();
|
|
expect(m?.featurePitch.description).toBeTruthy();
|
|
});
|
|
|
|
test('REQUIRED_TABLES lists all three subagent tables', () => {
|
|
expect(__testing.REQUIRED_TABLES).toEqual([
|
|
'subagent_messages',
|
|
'subagent_tool_executions',
|
|
'subagent_rate_leases',
|
|
]);
|
|
});
|
|
|
|
test('phaseASchema skips on dry-run', async () => {
|
|
// v0.41.37.0 #1605: phaseASchema is now async (in-process runMigrateOnlyCore).
|
|
const r = await __testing.phaseASchema({ dryRun: true, yes: true, noAutopilotInstall: true });
|
|
expect(r.status).toBe('skipped');
|
|
expect(r.detail).toBe('dry-run');
|
|
});
|
|
|
|
test('phaseBVerify skips on dry-run', async () => {
|
|
const r = await __testing.phaseBVerify({ dryRun: true, yes: true, noAutopilotInstall: true });
|
|
expect(r.status).toBe('skipped');
|
|
expect(r.detail).toBe('dry-run');
|
|
});
|
|
|
|
test('orchestrator in dry-run returns complete with both phases skipped', async () => {
|
|
const m = getMigration('0.16.0');
|
|
const result = await m!.orchestrator({ dryRun: true, yes: true, noAutopilotInstall: true });
|
|
expect(result.version).toBe('0.16.0');
|
|
expect(result.phases.length).toBe(2);
|
|
expect(result.phases.every(p => p.status === 'skipped')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('schema-embedded.ts contains subagent tables', () => {
|
|
test('embedded schema references all three subagent tables', async () => {
|
|
const { SCHEMA_SQL } = await import('../src/core/schema-embedded.ts');
|
|
expect(SCHEMA_SQL).toContain('CREATE TABLE IF NOT EXISTS subagent_messages');
|
|
expect(SCHEMA_SQL).toContain('CREATE TABLE IF NOT EXISTS subagent_tool_executions');
|
|
expect(SCHEMA_SQL).toContain('CREATE TABLE IF NOT EXISTS subagent_rate_leases');
|
|
expect(SCHEMA_SQL).toContain('idx_subagent_messages_job');
|
|
expect(SCHEMA_SQL).toContain('idx_subagent_tools_job');
|
|
expect(SCHEMA_SQL).toContain('idx_rate_leases_key_expires');
|
|
});
|
|
});
|
|
|
|
describe('pglite-schema.ts contains subagent tables', () => {
|
|
test('embedded PGLite schema references all three subagent tables', async () => {
|
|
const { PGLITE_SCHEMA_SQL } = await import('../src/core/pglite-schema.ts');
|
|
expect(PGLITE_SCHEMA_SQL).toContain('CREATE TABLE IF NOT EXISTS subagent_messages');
|
|
expect(PGLITE_SCHEMA_SQL).toContain('CREATE TABLE IF NOT EXISTS subagent_tool_executions');
|
|
expect(PGLITE_SCHEMA_SQL).toContain('CREATE TABLE IF NOT EXISTS subagent_rate_leases');
|
|
});
|
|
});
|