mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
test: coverage for ambient reflex-channel logging + watch window/cap flags
Ship coverage audit (85%, gate PASS) named five gaps; the two substantive cheap ones close here: the codex-D11 logChannel='reflex' path now has a behavioral pin (events land on channel 'reflex' through the drained sink; no logChannel → no events), and gbrain watch's --window-turns / --max-pages flags are exercised (turn-1 attribution under window=1; cap to one page). Remaining flagged-not-blocking: the wallclock-timeout branch (untestable without >10s real-clock flake — same rationale as the arming pin), formatResult's volunteer case (module-private), and the cycle purge wiring. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a5b117a085
commit
76ac3af529
@@ -289,3 +289,47 @@ describe('v0.43 (#2095) — rolling window extraction through assemble()', () =>
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ambient-channel event logging (codex D11 — logChannel: reflex)', () => {
|
||||
test('resolver with logChannel logs channel=reflex events through the drained sink', async () => {
|
||||
const { awaitPendingVolunteerEventWrites, _resetPendingVolunteerEventWritesForTests } =
|
||||
await import('../src/core/context/volunteer-events.ts');
|
||||
_resetPendingVolunteerEventWritesForTests();
|
||||
await engine.executeRaw('DELETE FROM context_volunteer_events').catch(() => {});
|
||||
await seed('people/alice-example', 'Alice Example', 'A founder.');
|
||||
|
||||
const block = await resolveEntitiesToPointers(
|
||||
engine,
|
||||
'default',
|
||||
extractCandidates('what do you think about Alice Example?'),
|
||||
{ logChannel: 'reflex' },
|
||||
);
|
||||
expect(block).not.toBeNull();
|
||||
const { unfinished } = await awaitPendingVolunteerEventWrites(5_000);
|
||||
expect(unfinished).toBe(0);
|
||||
const rows = await engine.executeRaw<{ channel: string; slug: string; match_arm: string }>(
|
||||
'SELECT channel, slug, match_arm FROM context_volunteer_events',
|
||||
[],
|
||||
);
|
||||
expect(rows.length).toBe(1);
|
||||
expect(rows[0].channel).toBe('reflex');
|
||||
expect(rows[0].slug).toBe('people/alice-example');
|
||||
expect(rows[0].match_arm).toBe('title');
|
||||
});
|
||||
|
||||
test('no logChannel → no events (the volunteer layer logs its own)', async () => {
|
||||
await engine.executeRaw('DELETE FROM context_volunteer_events').catch(() => {});
|
||||
await seed('people/alice-example', 'Alice Example', 'A founder.');
|
||||
const block = await resolveEntitiesToPointers(
|
||||
engine,
|
||||
'default',
|
||||
extractCandidates('about Alice Example'),
|
||||
{},
|
||||
);
|
||||
expect(block).not.toBeNull();
|
||||
const { awaitPendingVolunteerEventWrites } = await import('../src/core/context/volunteer-events.ts');
|
||||
await awaitPendingVolunteerEventWrites(5_000);
|
||||
const rows = await engine.executeRaw<{ channel: string }>('SELECT channel FROM context_volunteer_events', []);
|
||||
expect(rows.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -125,3 +125,31 @@ describe('gbrain watch (#2095)', () => {
|
||||
expect(out.join('')).toContain('people/alice-example');
|
||||
});
|
||||
});
|
||||
|
||||
describe('gbrain watch — window + cap flags (ship coverage G4)', () => {
|
||||
test('--window-turns 1: fires on the mention turn itself; the pronoun follow-up adds nothing', async () => {
|
||||
await seed('people/alice-example', 'Alice Example', 'Alice is a founder.');
|
||||
const out = await watchRun(
|
||||
[
|
||||
'assistant: Alice Example led one last year.',
|
||||
'user: what did she invest in?',
|
||||
],
|
||||
['--window-turns', '1', '--json'],
|
||||
);
|
||||
// Watch volunteers per turn: the entity fires at turn 1 (its mention
|
||||
// turn). With window=1 the follow-up turn extracts nothing, so exactly
|
||||
// one row exists and it carries turn 1 attribution.
|
||||
expect(out.length).toBe(1);
|
||||
expect(JSON.parse(out[0]).turn).toBe(1);
|
||||
});
|
||||
|
||||
test('--max-pages 1 caps a multi-entity turn to one volunteered page', async () => {
|
||||
await seed('people/alice-example', 'Alice Example', 'Founder.');
|
||||
await seed('people/bob-sample', 'Bob Sample', 'Engineer.');
|
||||
const out = await watchRun(
|
||||
['user: intro Alice Example to Bob Sample'],
|
||||
['--max-pages', '1', '--json'],
|
||||
);
|
||||
expect(out.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user