88aa122cf8
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
127 lines
5.7 KiB
JavaScript
127 lines
5.7 KiB
JavaScript
// tools/brain-retro-opus-reviewer.test.mjs — TDD for Phase 3 Task 18 (G16, spec §4.6)
|
|
import { describe, it, expect } from 'vitest';
|
|
import { buildReviewPrompt, buildReviewPromptStructured, parseReview } from './brain-retro-opus-reviewer.mjs';
|
|
|
|
describe('buildReviewPrompt — adaptive v2/v3/v4 (spec §4.6)', () => {
|
|
it('v4 includes alternatives_considered + self_assessment + chain_gaps cues', () => {
|
|
const ep = {
|
|
schema_version: 4,
|
|
schema_minor: 2,
|
|
task_id: 't',
|
|
primary_rationale: { task_classification: 'feature', node_chosen: 'direct' },
|
|
classifier_output: { recommended_node: '#19', alternatives_considered: [{ node: 'x', match_score: 0.5 }] },
|
|
self_assessment: { summary: 'ok', confidence_in_choice: 0.8 },
|
|
execution_trace: { chain_gaps: [] },
|
|
};
|
|
const p = buildReviewPrompt(ep);
|
|
expect(p).toContain('alternatives_considered');
|
|
expect(p).toContain('self_assessment');
|
|
expect(p).toContain('chain_gaps');
|
|
});
|
|
|
|
it('structured prompt returns a non-empty system block (caching target)', () => {
|
|
const { system, user } = buildReviewPromptStructured({ schema_version: 2 });
|
|
expect(typeof system).toBe('string');
|
|
expect(system.length).toBeGreaterThan(0);
|
|
expect(typeof user).toBe('string');
|
|
});
|
|
|
|
it('v3 omits alternatives_considered cue', () => {
|
|
expect(buildReviewPrompt({ schema_version: 3 })).not.toContain('alternatives_considered');
|
|
});
|
|
|
|
it('v2 omits alternatives + post-hoc self_assessment notes', () => {
|
|
const p = buildReviewPrompt({ schema_version: 2 });
|
|
expect(p).not.toContain('alternatives_considered');
|
|
// The "agent_self_assessment_accuracy" cue is part of the 8-dim contract
|
|
// (always present). What v2 must NOT have is the adaptive note that
|
|
// tells the reviewer to compare honesty against a post-hoc field — v2
|
|
// episodes do not carry one.
|
|
expect(p).not.toMatch(/self_assessment\s*\(if present/);
|
|
expect(p).not.toContain('post-hoc judgement');
|
|
});
|
|
|
|
it('includes the episode JSON verbatim for the reviewer to read', () => {
|
|
const ep = { schema_version: 4, task_id: 'task-xyz-1' };
|
|
expect(buildReviewPrompt(ep)).toContain('task-xyz-1');
|
|
});
|
|
});
|
|
|
|
describe('buildReviewPromptStructured — split for prompt caching', () => {
|
|
it('returns { system, user } with episode JSON only in user block', () => {
|
|
const ep = { schema_version: 4, task_id: 'task-cache-1' };
|
|
const { system, user } = buildReviewPromptStructured(ep);
|
|
expect(typeof system).toBe('string');
|
|
expect(typeof user).toBe('string');
|
|
expect(user).toContain('task-cache-1');
|
|
expect(system).not.toContain('task-cache-1');
|
|
});
|
|
|
|
it('system block carries the 8-dim cue contract', () => {
|
|
const { system } = buildReviewPromptStructured({ schema_version: 4 });
|
|
expect(system).toContain('node_quality');
|
|
expect(system).toContain('chain_quality');
|
|
expect(system).toContain('outcome_reviewed');
|
|
expect(system).toContain('reasoning');
|
|
});
|
|
|
|
it('system block is identical across two v4 episodes with different bodies (cache prerequisite)', () => {
|
|
const a = buildReviewPromptStructured({ schema_version: 4, task_id: 'a' }).system;
|
|
const b = buildReviewPromptStructured({ schema_version: 4, task_id: 'b', other: 'noise' }).system;
|
|
expect(a).toBe(b);
|
|
});
|
|
|
|
it('user block carries Episode (JSON): marker + final "Output JSON only."', () => {
|
|
const { user } = buildReviewPromptStructured({ schema_version: 4, task_id: 't' });
|
|
expect(user).toContain('Episode (JSON):');
|
|
expect(user.trim().endsWith('Output JSON only.')).toBe(true);
|
|
});
|
|
|
|
it('buildReviewPrompt remains a string concatenation of system + user (backward compat)', () => {
|
|
const ep = { schema_version: 4, task_id: 'compat-1' };
|
|
const { system, user } = buildReviewPromptStructured(ep);
|
|
const combined = buildReviewPrompt(ep);
|
|
expect(combined).toContain(system);
|
|
expect(combined).toContain(user);
|
|
});
|
|
});
|
|
|
|
describe('parseReview — 8-dim review schema (spec §4.6)', () => {
|
|
it('parses a complete 8-dim review JSON', () => {
|
|
const r = parseReview('{"node_quality":"correct","chain_quality":"n/a","gap_assessment":"n/a","agent_self_assessment_accuracy":"accurate","error_root_cause":"n/a","alternative_better":null,"outcome_reviewed":"success","reasoning":"x"}');
|
|
expect(r.node_quality).toBe('correct');
|
|
expect(r.outcome_reviewed).toBe('success');
|
|
expect(r.alternative_better).toBeNull();
|
|
expect(r.reasoning).toBe('x');
|
|
});
|
|
|
|
it('strips ```json fence', () => {
|
|
const r = parseReview('```json\n{"node_quality":"wrong_node","chain_quality":"missing_step","gap_assessment":"acceptable","agent_self_assessment_accuracy":"over_confident","error_root_cause":"wrong_skill","alternative_better":"#19","outcome_reviewed":"rework","reasoning":"y"}\n```');
|
|
expect(r.node_quality).toBe('wrong_node');
|
|
expect(r.alternative_better).toBe('#19');
|
|
});
|
|
|
|
it('returns null on malformed JSON', () => {
|
|
expect(parseReview('not json')).toBeNull();
|
|
});
|
|
|
|
it('returns null when required field missing', () => {
|
|
expect(parseReview('{"node_quality":"correct"}')).toBeNull();
|
|
});
|
|
|
|
it('returns reviewer_error passthrough when reviewer escalates', () => {
|
|
const r = parseReview('{"reviewer_error":"malformed episode"}');
|
|
expect(r?.reviewer_error).toBe('malformed episode');
|
|
});
|
|
});
|
|
|
|
describe('buildReviewPromptStructured classifierContext (config-seam §D1)', () => {
|
|
it('дефолт → Лидерра', () => {
|
|
expect(buildReviewPromptStructured({ schema_version: 4 }).system).toContain('Лидерра');
|
|
});
|
|
it('classifierContext инъектируется', () => {
|
|
expect(buildReviewPromptStructured({ schema_version: 4 }, { classifierContext: 'ProjZ' }).system)
|
|
.toContain('ProjZ');
|
|
});
|
|
});
|