import assert from 'node:assert/strict'; import test from 'node:test'; import { loadScenarioCatalog } from './catalog.mjs'; import { CORE_SCENARIO_IDS, selectImpactScenarios } from './impact.mjs'; test('docs-only changes use the compact core gate', async () => { const catalog = await loadScenarioCatalog(); const selection = selectImpactScenarios({ catalog, changedPaths: ['AGENTS.md', 'docs/local-dev.md'], }); assert.equal(selection.strategy, 'core'); assert.deepEqual(selection.selected_ids, catalog .map((scenario) => scenario.id) .filter((id) => CORE_SCENARIO_IDS.includes(id))); assert.equal(selection.unmapped_paths.length, 0); }); test('domain changes select the domain and dependency closure', async () => { const catalog = await loadScenarioCatalog(); const selection = selectImpactScenarios({ catalog, changedPaths: ['memory-v2-lifecycle.mjs'], }); assert.equal(selection.strategy, 'impact'); assert.deepEqual(selection.impact_groups, ['CHAT', 'MEM']); assert.equal(selection.selected_ids.includes('MEM-16'), true); assert.equal(selection.selected_ids.includes('CHAT-15'), true); assert.equal(selection.selected_ids.includes('BILL-07'), false); }); test('critical paths expand mapped domains and unmapped paths block release', async () => { const catalog = await loadScenarioCatalog(); const critical = selectImpactScenarios({ catalog, changedPaths: ['server.mjs'], }); assert.equal(critical.policy_version, 2); assert.equal(critical.strategy, 'impact'); assert.ok(critical.selected_total < catalog.length); assert.deepEqual( critical.impact_groups, ['AGENT', 'AUTH', 'CFG', 'CHAT', 'DATA', 'FILE', 'MS', 'PAGE'], ); assert.deepEqual(critical.full_gate_reasons, []); assert.throws( () => selectImpactScenarios({ catalog, changedPaths: ['new-runtime-kernel.mjs'], }), /unmapped runtime paths: new-runtime-kernel\.mjs/, ); assert.throws( () => selectImpactScenarios({ catalog, changedPaths: [], blockingReasons: ['deployed_commit_not_ancestor:abc'], }), /Impact selection is blocked/, ); }); test('release policy changes use mapped REL and CFG domains without selecting the catalog', async () => { const catalog = await loadScenarioCatalog(); const selection = selectImpactScenarios({ catalog, changedPaths: [ 'release-gate/impact.mjs', 'scripts/release-portal-canary-prod.sh', '.runtime/portal/server.mjs', ], }); assert.equal(selection.strategy, 'impact'); assert.deepEqual(selection.impact_groups, ['CFG', 'REL']); assert.ok(selection.selected_total < catalog.length); assert.equal(selection.changed_paths.includes('.runtime/portal/server.mjs'), true); });