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:
Garry Tan
2026-06-12 06:26:06 -07:00
co-authored by Claude Fable 5
parent a5b117a085
commit 76ac3af529
2 changed files with 72 additions and 0 deletions
+44
View File
@@ -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);
});
});
+28
View File
@@ -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);
});
});