ktg-plugin-marketplace/plugins/voyage/tests/lib/profile-resolver.test.mjs

62 lines
3.4 KiB
JavaScript

// tests/lib/profile-resolver.test.mjs
// v5.1.1 SC5 — non-interference cases for resolvePhaseModel().
// Verifies the new highest-priority lookup step (brief.phase_signals[phase].model)
// wins over --profile flag and VOYAGE_PROFILE env; falls through cleanly when
// no brief signal is present.
import { test } from 'node:test';
import { strict as assert } from 'node:assert';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { resolvePhaseModel } from '../../lib/profiles/resolver.mjs';
const __dirname = dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = join(__dirname, '..', '..');
const FIXTURE = (name) => join(REPO_ROOT, 'tests', 'fixtures', name);
test('resolvePhaseModel — Case 1: brief signal wins over VOYAGE_PROFILE env', () => {
// brief-effort-low.md pins all 4 phases to model: sonnet.
// env says premium (would normally select opus). Brief must win.
const r = resolvePhaseModel('research', FIXTURE('brief-effort-low.md'), [], { VOYAGE_PROFILE: 'premium' });
assert.equal(r.model, 'sonnet', `brief signal should beat env; got ${JSON.stringify(r)}`);
assert.equal(r.source, 'brief-signal');
});
test('resolvePhaseModel — Case 2: brief signal wins over --profile flag', () => {
// brief-effort-high.md pins all 4 phases to model: opus.
// flag says economy (would normally select sonnet). Brief must win.
const r = resolvePhaseModel('execute', FIXTURE('brief-effort-high.md'), ['--profile', 'economy'], {});
assert.equal(r.model, 'opus', `brief signal should beat flag; got ${JSON.stringify(r)}`);
assert.equal(r.source, 'brief-signal');
});
test('resolvePhaseModel — Case 3: no phase_signals → fallthrough to --profile flag', () => {
// brief-without-phase-signals fixture lacks phase_signals entirely.
// --profile balanced is set. Should return balanced.phase_models.plan (= opus per yaml).
const r = resolvePhaseModel('plan', FIXTURE('brief-without-phase-signals.md'), ['--profile', 'balanced'], {});
assert.equal(r.model, 'opus', `balanced.plan should be opus; got ${JSON.stringify(r)}`);
assert.equal(r.source, 'flag');
});
test('resolvePhaseModel — Case 4: phase not in PHASE_SIGNAL_PHASES falls through gracefully', () => {
// brief-effort-high.md has signals for the 4 supported phases.
// Asking for 'continue' (not in PHASE_SIGNAL_PHASES) must fall through.
// --profile premium is set, so continue resolves to premium.phase_models.continue (= opus).
const r = resolvePhaseModel('continue', FIXTURE('brief-effort-high.md'), ['--profile', 'premium'], {});
assert.equal(r.model, 'opus', `premium.continue should be opus; got ${JSON.stringify(r)}`);
assert.ok(r.source !== 'brief-signal', 'continue must not resolve via brief-signal');
});
test('resolvePhaseModel — Case 5 (defensive): missing brief file falls through cleanly', () => {
// Non-existent path. Must not throw; must fall through to flag/env/default.
const r = resolvePhaseModel('plan', '/nonexistent/brief.md', ['--profile', 'economy'], {});
assert.equal(r.model, 'sonnet', 'economy.plan should be sonnet on fallthrough');
assert.equal(r.source, 'flag');
});
test('resolvePhaseModel — Case 6 (defensive): null briefPath falls through to default', () => {
// null briefPath, no flag, no env → default = premium.
const r = resolvePhaseModel('plan', null, [], {});
assert.equal(r.model, 'opus', 'premium.plan default = opus');
assert.equal(r.source, 'default');
});