Files
gbrain/test/post-write-lint.test.ts
T
daragao3 dba0ae7b1e fix(validation): qualify backlink endpoint identity (#3667)
Adversarial review: survived a hostile reviewer plus two independent refuters, each told to assume the PR was broken and to default to refuting when uncertain. 19 of 62 PRs cleared that bar.

The back-link validator compared bare slugs, so a same-slug page in another source masked a genuinely missing reverse edge — silent under-reporting in exactly the multi-source setup where it matters. Now keyed on the full 4-tuple, per the `(source_id, slug)` uniqueness invariant. Verified on real Docker Postgres with 28/28 parity, which the PR itself had skipped.

Verified before merge: the PR's own tests fail when the production change is reverted; typecheck clean; MERGEABLE/CLEAN on the current base after batches 1 and 2 landed, not a stale one.

Known gap, recorded rather than hidden: remote MCP serialization of the additive Link fields is untested; the fields are additive JSON.
2026-08-01 03:39:12 +08:00

195 lines
7.2 KiB
TypeScript

/**
* Post-write validator lint tests (PR 2.5 minimal integration).
*
* Feature-flag gated; default OFF means zero behavior change to put_page.
* When ON, runs the 4 BrainWriter validators and logs findings without
* rejecting the write. Strict-mode flip is out of scope; deferred per
* CEO plan.
*/
import { describe, test, expect, beforeAll, afterAll, beforeEach } from 'bun:test';
import { tmpdir } from 'os';
import { mkdtempSync, rmSync } from 'fs';
import { join } from 'path';
import { PGLiteEngine } from '../src/core/pglite-engine.ts';
import type { BrainEngine } from '../src/core/engine.ts';
import { runPostWriteLint, isLintOnPutPageEnabled } from '../src/core/output/post-write.ts';
let engine: BrainEngine;
let dbDir: string;
beforeAll(async () => {
dbDir = mkdtempSync(join(tmpdir(), 'postwrite-'));
engine = new PGLiteEngine();
await engine.connect({ engine: 'pglite', database_path: dbDir });
await engine.initSchema();
});
afterAll(async () => {
await engine.disconnect();
rmSync(dbDir, { recursive: true, force: true });
});
async function reset(): Promise<void> {
await engine.executeRaw('TRUNCATE pages, links, content_chunks, timeline_entries, tags, raw_data, page_versions, ingest_log RESTART IDENTITY CASCADE');
await engine.executeRaw(`DELETE FROM config WHERE key = 'writer.lint_on_put_page'`);
}
describe('isLintOnPutPageEnabled', () => {
beforeEach(async () => { await reset(); });
test('defaults false when config unset', async () => {
expect(await isLintOnPutPageEnabled(engine)).toBe(false);
});
test('true when config = true', async () => {
await engine.setConfig('writer.lint_on_put_page', 'true');
expect(await isLintOnPutPageEnabled(engine)).toBe(true);
});
test('true when config = 1', async () => {
await engine.setConfig('writer.lint_on_put_page', '1');
expect(await isLintOnPutPageEnabled(engine)).toBe(true);
});
test('false for any other value', async () => {
await engine.setConfig('writer.lint_on_put_page', 'maybe');
expect(await isLintOnPutPageEnabled(engine)).toBe(false);
});
test('false when config = false', async () => {
await engine.setConfig('writer.lint_on_put_page', 'false');
expect(await isLintOnPutPageEnabled(engine)).toBe(false);
});
});
describe('runPostWriteLint', () => {
beforeEach(async () => { await reset(); });
test('flag disabled → returns ran=false, no findings', async () => {
await engine.putPage('people/x', {
type: 'person', title: 'X', compiled_truth: 'X has a bare factual paragraph without a citation.',
frontmatter: {},
});
const r = await runPostWriteLint(engine, 'people/x');
expect(r.ran).toBe(false);
expect(r.skippedReason).toBe('flag_disabled');
expect(r.findings).toEqual([]);
});
test('page not found → returns ran=false', async () => {
const r = await runPostWriteLint(engine, 'people/ghost', { force: true });
expect(r.ran).toBe(false);
expect(r.skippedReason).toBe('page_not_found');
});
test('validate:false frontmatter → skipped (grandfather)', async () => {
await engine.putPage('people/old', {
type: 'person', title: 'Old', compiled_truth: 'Lots of factual paragraphs without citations.',
frontmatter: { validate: false },
});
const r = await runPostWriteLint(engine, 'people/old', { force: true });
expect(r.ran).toBe(false);
expect(r.skippedReason).toBe('validate_false_frontmatter');
});
test('forces run even when flag is off', async () => {
await engine.putPage('people/y', {
type: 'person', title: 'Y', compiled_truth: 'Y raised money [Source: X, 2026-04-18](https://x.com/y).',
frontmatter: {},
});
const r = await runPostWriteLint(engine, 'people/y', { force: true, noLog: true });
expect(r.ran).toBe(true);
});
test('flag on + bad page → findings include citation error', async () => {
await engine.setConfig('writer.lint_on_put_page', 'true');
await engine.putPage('people/bad', {
type: 'person', title: 'Bad', compiled_truth: 'Bad raised $5M in Series A from Sequoia without citation.',
frontmatter: {},
});
const r = await runPostWriteLint(engine, 'people/bad', { noLog: true });
expect(r.ran).toBe(true);
expect(r.findings.length).toBeGreaterThan(0);
const citationError = r.findings.find(f => f.validator === 'citation' && f.severity === 'error');
expect(citationError).toBeDefined();
});
test('flag on + clean page → zero findings', async () => {
await engine.setConfig('writer.lint_on_put_page', 'true');
await engine.putPage('people/clean', {
type: 'person', title: 'Clean',
compiled_truth: '## See Also\n- [Source: X/clean, 2026-04-18](https://x.com/clean/status/1)',
frontmatter: {},
});
const r = await runPostWriteLint(engine, 'people/clean', { noLog: true });
expect(r.ran).toBe(true);
expect(r.findings).toEqual([]);
});
test('nested backlink reads preserve the exact non-default source', async () => {
await engine.executeRaw(
`INSERT INTO sources (id, name) VALUES ('team-x', 'team-x') ON CONFLICT (id) DO NOTHING`,
);
for (const sourceId of ['default', 'team-x']) {
await engine.putPage('notes/source-backlink', {
type: 'note', title: `Origin ${sourceId}`,
compiled_truth: '## See Also\n- [Source: X/origin, 2026-04-18](https://x.com/origin/1)',
frontmatter: {},
}, { sourceId });
await engine.putPage('people/target', {
type: 'person', title: `Target ${sourceId}`,
compiled_truth: '## See Also\n- [Source: X/target, 2026-04-18](https://x.com/target/1)',
frontmatter: {},
}, { sourceId });
}
await engine.addLink(
'notes/source-backlink', 'people/target', 'forward', 'mentions', 'manual', undefined, undefined,
{ fromSourceId: 'team-x', toSourceId: 'team-x' },
);
await engine.addLink(
'people/target', 'notes/source-backlink', 'wrong reverse', 'mentions', 'manual', undefined, undefined,
{ fromSourceId: 'team-x', toSourceId: 'default' },
);
const r = await runPostWriteLint(engine, 'notes/source-backlink', {
force: true,
noLog: true,
sourceId: 'team-x',
});
expect(r.ran).toBe(true);
expect(r.findings).toContainEqual(expect.objectContaining({
validator: 'back-link',
severity: 'warning',
}));
});
test('nested markdown-link reads do not fall through to a same-slug page in another source', async () => {
await engine.executeRaw(
`INSERT INTO sources (id, name) VALUES ('team-x', 'team-x') ON CONFLICT (id) DO NOTHING`,
);
await engine.putPage('notes/source-link', {
type: 'note', title: 'Team origin',
compiled_truth: '[Target](people/target.md)',
frontmatter: {},
}, { sourceId: 'team-x' });
await engine.putPage('people/target', {
type: 'person', title: 'Default-only target', compiled_truth: 'target', frontmatter: {},
}, { sourceId: 'default' });
const r = await runPostWriteLint(engine, 'notes/source-link', {
force: true,
noLog: true,
sourceId: 'team-x',
});
expect(r.findings).toContainEqual(expect.objectContaining({
validator: 'link',
severity: 'error',
message: expect.stringContaining('people/target'),
}));
});
});