mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
* fix(extract,ingest): well-form lone UTF-16 surrogates before jsonb (#2011) excerpt() in link-extraction.ts sliced the link-context window by raw UTF-16 index, so a boundary landing inside a non-BMP char (emoji, math, CJK) left an unpaired surrogate half in `context`. Serialized to JSONB for the jsonb_to_recordset batch insert, Postgres rejects it at the ::jsonb cast and aborts the whole batch — wedging `extract --stale` because the staleness bookmark only advances on a clean finish. - text-safe.ts: new ensureWellFormed() (Bun isWellFormed/toWellFormed) — one shared surrogate-cleaning primitive. - link-extraction.ts: excerpt() well-forms the slice (root-cause fix). - batch-rows.ts: new sanitizeForJsonb() = ensureWellFormed(stripNul(s)) applied to every free-text body field (link context; timeline summary/detail/source; take claim/source). Identity/security fields stay un-sanitized and fail closed. - postgres-engine.ts + pglite-engine.ts: scalar addLink + addTimelineEntry use sanitizeForJsonb too, matching the batch path on both engines. - brainstorm/orchestrator.ts: consolidate hand-rolled sanitizeUnicode onto ensureWellFormed (also fixes consecutive-lone-surrogate mishandling). Tests: ensureWellFormed unit cases (incl. consecutive lone surrogates), an excerpt window-split regression, PGLite + Postgres-e2e surrogate cases across all free-text fields and scalar paths, and fail-closed identity-field tests proving sanitization was NOT extended to slugs/holders. * v0.42.39.0 chore: bump version and changelog (#2011) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: update project documentation for v0.42.39.0 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * v0.42.40.0 chore: re-slot release version (was 0.42.39.0) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: fix env-mutation isolation violations in retrieval-reflex tests check:test-isolation (rule R1) flags direct process.env mutation in non-serial test files — bun's parallel runner loads multiple files into one process, so a leaked GBRAIN_RETRIEVAL_REFLEX flips reflex behavior in unrelated tests. Both files landed via the #2019 merge; convert the beforeEach/afterEach env juggling to the canonical withEnv() wrapper, which restores the prior value via try/finally even on throw. Fixes the failing `verify` CI check on #2031 (and the `test-status` aggregate that inherits it). All 30 verify checks green locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
45 lines
1.9 KiB
TypeScript
45 lines
1.9 KiB
TypeScript
/**
|
|
* Doctor retrieval_reflex_health check (#1981, T8).
|
|
*/
|
|
import { describe, test, expect } from 'bun:test';
|
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { buildRetrievalReflexCheck } from '../src/commands/doctor.ts';
|
|
import { withEnv } from './helpers/with-env.ts';
|
|
|
|
describe('buildRetrievalReflexCheck', () => {
|
|
test('disabled via env → warn, names the right check', async () => {
|
|
await withEnv({ GBRAIN_RETRIEVAL_REFLEX: 'false' }, async () => {
|
|
const c = buildRetrievalReflexCheck(null);
|
|
expect(c.name).toBe('retrieval_reflex_health');
|
|
expect(c.status).toBe('warn');
|
|
expect(c.message).toContain('disabled');
|
|
expect((c.details as any)?.enabled).toBe(false);
|
|
});
|
|
});
|
|
|
|
test('enabled → reports policy-skill install state in details', async () => {
|
|
await withEnv({ GBRAIN_RETRIEVAL_REFLEX: 'true' }, async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'rr-doctor-'));
|
|
mkdirSync(join(dir, 'retrieval-reflex'), { recursive: true });
|
|
writeFileSync(join(dir, 'retrieval-reflex', 'SKILL.md'), '# stub\n');
|
|
const c = buildRetrievalReflexCheck(dir);
|
|
expect(c.name).toBe('retrieval_reflex_health');
|
|
expect((c.details as any)?.enabled).toBe(true);
|
|
expect((c.details as any)?.policy_skill_installed).toBe(true);
|
|
rmSync(dir, { recursive: true, force: true });
|
|
});
|
|
});
|
|
|
|
test('enabled, policy skill absent → message includes the install hint', async () => {
|
|
await withEnv({ GBRAIN_RETRIEVAL_REFLEX: 'true' }, async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'rr-doctor-2-'));
|
|
const c = buildRetrievalReflexCheck(dir);
|
|
expect((c.details as any)?.policy_skill_installed).toBe(false);
|
|
expect(c.message).toContain('gbrain integrations install retrieval-reflex');
|
|
rmSync(dir, { recursive: true, force: true });
|
|
});
|
|
});
|
|
});
|