Files
TORCH/test/fleet/runtime-profiles.test.mjs

476 lines
27 KiB
JavaScript

import assert from 'node:assert/strict';
import { execFileSync, spawnSync } from 'node:child_process';
import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { basename, join } from 'node:path';
import test from 'node:test';
import { createClaudeAdapter } from '../../src/adapters/claude.mjs';
import { createCodexAdapter } from '../../src/adapters/codex.mjs';
import { createPiAdapter } from '../../src/adapters/pi.mjs';
import { createRuntimeAdapterRegistry } from '../../src/adapters/registry.mjs';
import { createConsoleServer } from '../../src/console/server.mjs';
import { openControlPlane } from '../../src/control-plane/service.mjs';
import { analyzeRepository } from '../../src/kernel/analyze.mjs';
import { proposeDomains } from '../../src/kernel/domains.mjs';
import { diagnoseProject } from '../../src/kernel/doctor.mjs';
import { inspectRepository } from '../../src/kernel/git.mjs';
import { installProject } from '../../src/kernel/install.mjs';
import { createWorktrees } from '../../src/kernel/worktrees.mjs';
import { planAreaUp, planFleetUp } from '../../src/runtime/lifecycle.mjs';
import { unsupportedCapability } from '../../src/adapters/runtime.mjs';
import { observeProject } from '../../src/observability/snapshot.mjs';
function localAdapter() {
return {
name: 'local-agent',
configuration: { worker_pool: 'local' },
capabilities: {
detect: true, configure: 'plan-only', modelSelection: true, reasoningSelection: true,
perInvocationCostCeiling: { createSession: [], resumeSession: [] },
createSession: true, resumeSession: true, sendOrSteer: false, getStatus: false,
listSessions: false, stopSession: false, captureRuntimeId: false,
installHooks: false, removeHooks: false,
},
detect: () => ({ available: true, adapter: 'local-agent' }),
configure: ({ repositoryRoot, areaId }) => ({
adapter: 'local-agent', mutationPerformed: false,
mcp: { name: `torch-${areaId}`, command: process.execPath, args: [], cwd: repositoryRoot },
}),
createSession: ({ areaId, worktree, model, reasoning }) => ({
adapter: 'local-agent', areaId, runtimeSessionId: null,
requiresRuntimeIdCapture: false,
profile: { model, reasoning },
launch: { command: 'local-agent', args: [model, reasoning], cwd: worktree, mutatesRuntime: true },
}),
resumeSession: ({ areaId, runtimeSessionId, worktree, model, reasoning }) => ({
adapter: 'local-agent', areaId, runtimeSessionId,
profile: { model, reasoning },
launch: { command: 'local-agent', args: [model, reasoning], cwd: worktree, mutatesRuntime: true },
}),
sendOrSteer() { return unsupportedCapability(this.name, 'sendOrSteer'); },
getStatus() { return unsupportedCapability(this.name, 'getStatus'); },
listSessions() { return unsupportedCapability(this.name, 'listSessions'); },
stopSession() { return unsupportedCapability(this.name, 'stopSession'); },
captureRuntimeId() { return unsupportedCapability(this.name, 'captureRuntimeId'); },
installHooks() { return unsupportedCapability(this.name, 'installHooks'); },
removeHooks() { return unsupportedCapability(this.name, 'removeHooks'); },
};
}
function fixture(registry) {
const root = mkdtempSync(join(tmpdir(), 'torch-runtime-profiles-'));
const env = { ...process.env, XDG_DATA_HOME: join(tmpdir(), `${basename(root)}-state`) };
execFileSync('git', ['init', '-b', 'main', root]);
execFileSync('git', ['-C', root, 'config', 'user.email', '[email protected]']);
execFileSync('git', ['-C', root, 'config', 'user.name', 'TORCH Test']);
writeFileSync(join(root, 'app.js'), 'export const app = true;\n');
execFileSync('git', ['-C', root, 'add', '.']);
execFileSync('git', ['-C', root, 'commit', '-m', 'fixture']);
const repository = inspectRepository(root);
const proposal = proposeDomains({ repository, analysis: analyzeRepository(repository) });
const worker = proposal.domains[0];
worker.runtime = 'codex';
worker.model = 'gpt-worker';
worker.reasoning = null;
worker.resources = [];
proposal.session_manager = {
runtime: 'claude', model: 'claude-manager', reasoning: 'high',
};
proposal.domains.push({
id: 'docs', title: 'Documentation', scope: ['documentation maintenance'],
not_scope: ['application implementation'], owned_paths: ['docs/**'], shared_paths: [],
neighbours: [worker.id], required_checks: [], resources: [],
runtime: 'local-agent', model: 'manual-model', reasoning: 'deep',
});
proposal.domains.push({
id: 'codex-defaults', title: 'Codex Defaults', scope: ['default Codex profile'],
not_scope: ['application implementation'], owned_paths: ['defaults/**'], shared_paths: [],
neighbours: [], required_checks: [], resources: [], runtime: 'codex',
});
proposal.review = {
status: 'approved', reviewedAt: '2026-09-28T00:00:00Z', reviewedBy: 'fixture-owner', notes: [],
};
installProject({
repository, proposal, env, projectId: 'runtime-profile-fixture',
runtimes: ['claude', 'codex', 'local-agent'], runtimeRegistry: registry,
});
execFileSync('git', ['-C', root, 'add', '.torch']);
execFileSync('git', ['-C', root, 'commit', '-m', 'install torch']);
createWorktrees({ repository: inspectRepository(root), parentOverride: join(tmpdir(), `${basename(root)}-worktrees`) });
return { root, env, worker: worker.id };
}
test('SCN-runtime-profiles: each identity launches through its assigned adapter and profile', () => {
const registry = createRuntimeAdapterRegistry({ adapters: [localAdapter()] });
const context = fixture(registry);
const control = openControlPlane({ repositoryRoot: context.root, env: context.env });
const adapters = registry.toMap();
adapters.set('codex', createCodexAdapter({ executable: 'codex' }));
adapters.set('claude', createClaudeAdapter({ executable: 'claude' }));
const plan = planFleetUp({
repositoryRoot: context.root, controlPlane: control, adapters, fresh: true,
});
assert.equal(plan.canProceed, true, JSON.stringify(plan.blockers));
const worker = plan.actions.find((action) => action.areaId === context.worker);
const docs = plan.actions.find((action) => action.areaId === 'docs');
const manager = plan.actions.find((action) => action.areaId === 'session-manager');
const defaultCodex = plan.actions.find((action) => action.areaId === 'codex-defaults');
assert.equal(worker.runtime, 'codex');
assert.deepEqual(worker.profile, { model: 'gpt-worker', reasoning: 'high', launchPolicy: { approval: 'approve-for-me' } });
assert.equal(worker.launch.args.includes('gpt-worker'), true);
assert.equal(worker.profile.reasoning, 'high', 'omitted identity reasoning inherits Codex default');
assert.equal(manager.runtime, 'claude');
assert.deepEqual(manager.profile, { model: 'claude-manager', reasoning: 'high', launchPolicy: {} });
assert.deepEqual(manager.launch.args.slice(manager.launch.args.indexOf('--effort'), manager.launch.args.indexOf('--effort') + 2), ['--effort', 'high']);
assert.deepEqual(defaultCodex.profile, { model: 'gpt-6-luna', reasoning: 'high', launchPolicy: { approval: 'approve-for-me' } });
assert.equal(defaultCodex.launch.args.includes('gpt-6-luna'), true);
assert.equal(defaultCodex.launch.args.includes('model_reasoning_effort="high"'), true);
assert.deepEqual(
(({ runtime, model, reasoning }) => ({ runtime, model, reasoning }))(control.identity('codex-defaults')),
{ runtime: 'codex', model: 'gpt-6-luna', reasoning: 'high' },
'live identity query resolves and exposes the configured adapter defaults',
);
assert.deepEqual(
(({ runtime, model, reasoning }) => ({ runtime, model, reasoning }))(control.identity('session-manager')),
{ runtime: 'claude', model: 'claude-manager', reasoning: 'high' },
'identity-specific runtime profile overrides remain visible',
);
assert.equal(docs.runtime, 'local-agent');
assert.deepEqual(docs.profile, { model: 'manual-model', reasoning: 'deep', launchPolicy: {} });
assert.deepEqual(docs.launch.args, ['manual-model', 'deep']);
assert.equal(plan.mutationPerformed, false);
const configPath = join(context.root, '.torch', 'torch.yaml');
const config = JSON.parse(readFileSync(configPath, 'utf8'));
assert.deepEqual(config.runtimes.codex, {
model: 'gpt-6-luna', reasoning: 'high', launchPolicy: { approval: 'approve-for-me' },
});
assert.deepEqual(config.runtimes.claude, { model: 'sonnet', background: true });
assert.equal(config.session_manager.model, 'claude-manager', 'identity overrides remain independent');
config.runtimes.codex.launchPolicy = { sandbox: 'workspace-write', approval: 'on-request' };
config.domains.find((area) => area.id === context.worker).launchPolicy = { approval: 'never' };
config.session_manager.launchPolicy = { permissionMode: 'acceptEdits' };
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
const policyPlan = planFleetUp({ repositoryRoot: context.root, controlPlane: control, adapters, fresh: true });
assert.equal(policyPlan.canProceed, true, JSON.stringify(policyPlan.blockers));
const policyWorker = policyPlan.actions.find((action) => action.areaId === context.worker);
const policyDefault = policyPlan.actions.find((action) => action.areaId === 'codex-defaults');
const policyManager = policyPlan.actions.find((action) => action.areaId === 'session-manager');
assert.deepEqual(policyWorker.profile.launchPolicy, { sandbox: 'workspace-write', approval: 'never' });
assert.ok(policyWorker.launch.args.includes('--sandbox'));
assert.ok(policyWorker.launch.args.includes('workspace-write'));
assert.ok(policyWorker.launch.args.includes('--ask-for-approval'));
assert.ok(policyWorker.launch.args.includes('never'));
assert.deepEqual(policyDefault.profile.launchPolicy, { sandbox: 'workspace-write', approval: 'on-request' });
assert.ok(policyDefault.launch.args.includes('--ask-for-approval'));
assert.ok(policyDefault.launch.args.includes('on-request'));
assert.ok(policyManager.launch.args.includes('--permission-mode'));
assert.ok(policyManager.launch.args.includes('acceptEdits'));
assert.equal(policyPlan.mutationPerformed, false, 'policy resolution only changes a future launch plan');
assert.equal(policyPlan.actions.every((action) => action.launch.mutatesRuntime), true, 'plan describes launches but starts none');
const invalidConfig = JSON.parse(readFileSync(configPath, 'utf8'));
invalidConfig.runtimes.codex.launchPolicy = { sandbox: 'workspace-write', approval: 'approve-for-me' };
writeFileSync(configPath, `${JSON.stringify(invalidConfig, null, 2)}\n`);
const conflictPlan = planFleetUp({ repositoryRoot: context.root, controlPlane: control, adapters, fresh: true });
assert.equal(conflictPlan.canProceed, false);
assert.ok(conflictPlan.blockers.some((blocker) => blocker.code === 'RUNTIME_PROFILE_UNSUPPORTED'
&& blocker.capabilities.some((issue) => issue.conflictsWith === 'launchPolicy.sandbox')));
invalidConfig.runtimes.codex.launchPolicy = { approval: 'never' };
invalidConfig.domains.find((area) => area.id === 'docs').launchPolicy = { permissionMode: 'bypassPermissions' };
writeFileSync(configPath, `${JSON.stringify(invalidConfig, null, 2)}\n`);
const unsafePlan = planFleetUp({ repositoryRoot: context.root, controlPlane: control, adapters, fresh: true });
assert.equal(unsafePlan.canProceed, false, 'unsafe Claude permission modes block before execution');
assert.ok(unsafePlan.blockers.some((blocker) => blocker.areaId === 'docs' && blocker.code === 'RUNTIME_PROFILE_UNSUPPORTED'));
invalidConfig.domains.find((area) => area.id === 'docs').launchPolicy = { sandbox: 'workspace-write' };
writeFileSync(configPath, `${JSON.stringify(invalidConfig, null, 2)}\n`);
const unsupportedPlan = planFleetUp({ repositoryRoot: context.root, controlPlane: control, adapters, fresh: true });
assert.equal(unsupportedPlan.canProceed, false, 'custom adapter without a launch-policy declaration fails closed');
assert.ok(unsupportedPlan.blockers.some((blocker) => blocker.areaId === 'docs' && blocker.code === 'RUNTIME_PROFILE_UNSUPPORTED'));
delete invalidConfig.domains.find((area) => area.id === 'docs').launchPolicy;
writeFileSync(configPath, `${JSON.stringify(invalidConfig, null, 2)}\n`);
const snapshot = observeProject({ repositoryRoot: context.root, env: context.env, runtimeRegistry: registry });
assert.deepEqual(
snapshot.agents.find((agent) => agent.areaId === 'codex-defaults')
&& { model: snapshot.agents.find((agent) => agent.areaId === 'codex-defaults').model,
reasoning: snapshot.agents.find((agent) => agent.areaId === 'codex-defaults').reasoning },
{ model: 'gpt-6-luna', reasoning: 'high' },
'dashboard snapshot surfaces effective adapter defaults',
);
config.runtimes.codex.reasoning = 'medium';
config.runtimes.codex.model = 'gpt-6-luna-custom';
writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
const editedProfilePlan = planFleetUp({
repositoryRoot: context.root, controlPlane: control, adapters, fresh: true,
});
assert.equal(editedProfilePlan.canProceed, true, 'owner can change the project default without replacing the adapter');
const editedDefault = editedProfilePlan.actions.find((action) => action.areaId === 'codex-defaults');
assert.deepEqual(editedDefault.profile, {
model: 'gpt-6-luna-custom', reasoning: 'medium',
launchPolicy: { sandbox: 'workspace-write', approval: 'on-request' },
});
assert.equal(editedDefault.launch.args.includes('gpt-6-luna-custom'), true);
assert.equal(editedDefault.launch.args.includes('model_reasoning_effort="medium"'), true);
assert.equal(editedProfilePlan.mutationPerformed, false, 'profile changes only affect a future reviewed launch');
const editedSnapshot = observeProject({ repositoryRoot: context.root, env: context.env, runtimeRegistry: registry });
const editedAgent = editedSnapshot.agents.find((agent) => agent.areaId === 'codex-defaults');
assert.deepEqual({ model: editedAgent.model, reasoning: editedAgent.reasoning }, {
model: 'gpt-6-luna-custom', reasoning: 'medium',
});
const diagnosis = diagnoseProject({
repository: inspectRepository(context.root), env: context.env, runtimeRegistry: registry,
});
assert.equal(diagnosis.findings.some((finding) => finding.code === 'RUNTIME_PROFILE_UNSUPPORTED'), false);
assert.equal(diagnosis.findings.some((finding) => finding.code === 'RUNTIME_ADAPTER_UNKNOWN'
&& finding.runtime === 'local-agent'), false);
control.close();
});
test('SCN-runtime-cost-ceiling: exact session mode must declare and return an enforced per-invocation USD cap', () => {
const builtinAdapters = [
createClaudeAdapter({ executable: 'claude' }),
createCodexAdapter({ executable: 'codex' }),
createPiAdapter({ executable: 'pi' }),
];
for (const adapter of builtinAdapters) {
assert.deepEqual(adapter.capabilities.perInvocationCostCeiling, {
createSession: [], resumeSession: [],
});
}
const local = localAdapter();
local.capabilities = {
...local.capabilities,
perInvocationCostCeiling: { createSession: ['fixture-hard-cap'], resumeSession: [] },
};
const create = local.createSession;
local.createSession = (input) => {
const plan = create(input);
if (input.maxCostUsd === undefined) return plan;
return {
...plan,
costCeiling: { enforced: true, maxUsd: input.maxCostUsd, mode: 'fixture-hard-cap' },
launch: { ...plan.launch, args: [...plan.launch.args, '--max-cost-usd', String(input.maxCostUsd)] },
};
};
const registry = createRuntimeAdapterRegistry({ adapters: [local] });
const context = fixture(registry);
const control = openControlPlane({ repositoryRoot: context.root, env: context.env });
const uncapped = planAreaUp({
repositoryRoot: context.root, controlPlane: control, areaId: 'session-manager',
adapter: createClaudeAdapter({ executable: 'claude' }), maxCostUsd: 0.25,
});
assert.equal(uncapped.canProceed, false);
assert.equal(uncapped.actions.length, 0);
assert.equal(uncapped.blockers[0].code, 'RUNTIME_COST_CEILING_UNSUPPORTED');
const capped = planAreaUp({
repositoryRoot: context.root, controlPlane: control, areaId: 'docs', adapter: local, maxCostUsd: 0.25,
});
assert.equal(capped.canProceed, true, JSON.stringify(capped.blockers));
assert.deepEqual(capped.actions[0].costCeiling, {
enforced: true, maxUsd: 0.25, mode: 'fixture-hard-cap',
});
assert.deepEqual(capped.actions[0].launch.args.slice(-2), ['--max-cost-usd', '0.25']);
assert.equal(capped.mutationPerformed, false, 'planning does not invoke the runtime');
const deceptive = {
...local,
createSession: (input) => ({
...local.createSession(input),
costCeiling: { enforced: true, maxUsd: 10, mode: 'fixture-hard-cap' },
}),
};
const rejected = planAreaUp({
repositoryRoot: context.root, controlPlane: control, areaId: 'docs', adapter: deceptive, maxCostUsd: 0.25,
});
assert.equal(rejected.canProceed, false, 'an adapter receipt for a different cap must fail closed');
assert.equal(rejected.actions.length, 0);
assert.equal(rejected.blockers[0].code, 'RUNTIME_COST_CEILING_UNPROVEN');
control.close();
});
test('SCN-runtime-profile-cli: owner can change and reset project-local profiles without launching sessions', () => {
const context = fixture(createRuntimeAdapterRegistry({ adapters: [localAdapter()] }));
const cli = new URL('../../bin/torch.mjs', import.meta.url).pathname;
const run = (...args) => spawnSync(process.execPath, [cli, 'profile', ...args], {
cwd: context.root, env: context.env, encoding: 'utf8',
});
const shown = run('show', '--area', 'codex-defaults', '--json');
assert.equal(shown.status, 0, shown.stderr);
assert.deepEqual(JSON.parse(shown.stdout), {
areaId: 'codex-defaults', runtime: 'codex', model: 'gpt-6-luna', reasoning: 'high',
launchPolicy: { approval: 'approve-for-me' },
overrides: { runtime: true, model: false, reasoning: false, launchPolicy: false },
});
const refused = run('set', '--area', 'codex-defaults', '--model', 'gpt-custom', '--json');
assert.equal(refused.status, 2);
assert.match(refused.stdout, /--yes/);
const dryRun = run('set', '--area', 'codex-defaults', '--runtime', 'claude', '--model', 'dry-run-opus', '--dry-run', '--json');
assert.equal(dryRun.status, 0, dryRun.stderr);
assert.equal(JSON.parse(dryRun.stdout).beforeProfile.runtime, 'codex');
assert.equal(JSON.parse(dryRun.stdout).profile.runtime, 'claude');
assert.equal(JSON.parse(dryRun.stdout).mutationPerformed, false);
const configPath = join(context.root, '.torch', 'torch.yaml');
const legacyConfig = JSON.parse(readFileSync(configPath, 'utf8'));
delete legacyConfig.runtimes.codex.launchPolicy;
legacyConfig.runtimes.codex.sandbox = 'workspace-write';
legacyConfig.runtimes.codex.approval = 'approve-for-me';
writeFileSync(configPath, `${JSON.stringify(legacyConfig, null, 2)}\n`);
const migrated = run('defaults', '--runtime', 'codex', '--launch-policy', 'approval=never', '--yes', '--json');
assert.equal(migrated.status, 0, migrated.stderr);
assert.deepEqual(JSON.parse(migrated.stdout).profile.launchPolicy, {
sandbox: 'workspace-write', approval: 'never',
});
const migratedConfig = JSON.parse(readFileSync(configPath, 'utf8'));
assert.deepEqual(migratedConfig.runtimes.codex.launchPolicy, {
sandbox: 'workspace-write', approval: 'never',
}, 'leaving the implicit approve-for-me mode preserves its workspace-write sandbox');
assert.equal(Object.hasOwn(migratedConfig.runtimes.codex, 'sandbox'), false);
assert.equal(Object.hasOwn(migratedConfig.runtimes.codex, 'approval'), false);
const migratedArgs = createCodexAdapter({ executable: 'codex' }).createSession({
areaId: 'migrated', worktree: context.root, promptFile: '/tmp/prompt.md', firstMessage: 'start',
model: 'gpt-6-luna', launchPolicy: migratedConfig.runtimes.codex.launchPolicy,
}).launch.args;
assert.deepEqual(migratedArgs.slice(migratedArgs.indexOf('--sandbox'), migratedArgs.indexOf('--sandbox') + 2),
['--sandbox', 'workspace-write']);
assert.deepEqual(migratedArgs.slice(migratedArgs.indexOf('--ask-for-approval'), migratedArgs.indexOf('--ask-for-approval') + 2),
['--ask-for-approval', 'never']);
const resetPolicy = run('defaults', '--runtime', 'codex', '--reset-launch-policy', '--yes', '--json');
assert.equal(resetPolicy.status, 0, resetPolicy.stderr);
assert.deepEqual(JSON.parse(resetPolicy.stdout).profile.launchPolicy, { approval: 'approve-for-me' });
const changed = run(
'set', '--area', 'codex-defaults', '--runtime', 'claude', '--model', 'opus', '--reasoning', 'high', '--yes', '--json',
);
assert.equal(changed.status, 0, changed.stderr);
const changeReceipt = JSON.parse(changed.stdout);
assert.deepEqual(changeReceipt.profile, {
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
launchPolicy: {},
overrides: { runtime: true, model: true, reasoning: true, launchPolicy: false },
});
assert.equal(changeReceipt.sessionsStarted, false);
assert.equal(changeReceipt.existingSessionChanged, false);
const reset = run('set', '--area', 'codex-defaults', '--reset', '--yes', '--json');
assert.equal(reset.status, 0, reset.stderr);
assert.deepEqual(JSON.parse(reset.stdout).profile, {
areaId: 'codex-defaults', runtime: 'claude', model: 'sonnet', reasoning: null,
launchPolicy: {},
overrides: { runtime: true, model: false, reasoning: false, launchPolicy: false },
});
const config = JSON.parse(readFileSync(join(context.root, '.torch', 'torch.yaml'), 'utf8'));
assert.equal(config.domains.find((area) => area.id === 'codex-defaults').runtime, 'claude');
assert.equal(Object.hasOwn(config.domains.find((area) => area.id === 'codex-defaults'), 'model'), false);
assert.equal(Object.hasOwn(config.domains.find((area) => area.id === 'codex-defaults'), 'reasoning'), false);
const defaults = run('defaults', '--runtime', 'codex', '--model', 'gpt-custom', '--reasoning', 'medium', '--yes', '--json');
assert.equal(defaults.status, 0, defaults.stderr);
assert.deepEqual(JSON.parse(defaults.stdout).profile, {
model: 'gpt-custom', reasoning: 'medium', launchPolicy: { approval: 'approve-for-me' },
});
const workerProfile = run('show', '--area', context.worker, '--json');
assert.equal(workerProfile.status, 0, workerProfile.stderr);
assert.deepEqual(JSON.parse(workerProfile.stdout), {
areaId: context.worker, runtime: 'codex', model: 'gpt-worker', reasoning: 'medium',
launchPolicy: { approval: 'approve-for-me' },
overrides: { runtime: true, model: true, reasoning: false, launchPolicy: false },
});
const audit = openControlPlane({ repositoryRoot: context.root, env: context.env });
const profileEvents = audit.database.prepare(`
SELECT actor_id, entity_type, entity_id FROM audit_events WHERE operation = 'profile.change' ORDER BY rowid
`).all();
assert.equal(profileEvents.length, 5, 'confirmed identity and default edits are audited, dry runs are not');
assert.ok(profileEvents.every((entry) => entry.actor_id === 'owner'));
assert.equal(profileEvents.some((entry) => entry.entity_id === 'codex-defaults'), true);
audit.close();
});
test('SCN-console-runtime-profile: owner previews and confirms an audited next-launch profile without touching running sessions', async (context) => {
const fixtureState = fixture(createRuntimeAdapterRegistry({ adapters: [localAdapter()] }));
const server = createConsoleServer({ repositoryRoot: fixtureState.root, env: fixtureState.env });
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
context.after(() => server.close());
const origin = `http://127.0.0.1:${server.address().port}`;
const post = (path, body, requestOrigin = origin) => fetch(`${origin}${path}`, {
method: 'POST', headers: { origin: requestOrigin, 'content-type': 'application/json', 'sec-fetch-site': 'same-origin' },
body: JSON.stringify(body),
});
const configPath = join(fixtureState.root, '.torch', 'torch.yaml');
const configBefore = readFileSync(configPath, 'utf8');
const crossOrigin = await post('/api/runtime-profiles/preview', {
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
}, 'http://attacker.invalid');
assert.equal(crossOrigin.status, 403);
const firstPreviewResponse = await post('/api/runtime-profiles/preview', {
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
});
assert.equal(firstPreviewResponse.status, 200);
const firstPreview = await firstPreviewResponse.json();
assert.equal(firstPreview.plan.mutationPerformed, false);
assert.equal(firstPreview.plan.beforeProfile.runtime, 'codex');
assert.equal(firstPreview.plan.profile.runtime, 'claude');
assert.equal(firstPreview.plan.profile.model, 'opus');
assert.equal(firstPreview.plan.resetLaunchPolicy, true);
assert.match(firstPreview.plan.effect, /future launch plans only/);
assert.equal(readFileSync(configPath, 'utf8'), configBefore, 'preview is read-only');
const changedConfig = JSON.parse(configBefore);
changedConfig.runtimes.claude.reasoning = 'medium';
writeFileSync(configPath, `${JSON.stringify(changedConfig, null, 2)}\n`);
const stale = await post('/api/runtime-profiles', {
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
token: firstPreview.token, planHash: firstPreview.planHash,
});
assert.equal(stale.status, 409);
assert.equal((await stale.json()).error, 'RUNTIME_PROFILE_PREVIEW_STALE');
const previewResponse = await post('/api/runtime-profiles/preview', {
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
});
assert.equal(previewResponse.status, 200);
const preview = await previewResponse.json();
const payload = {
areaId: 'codex-defaults', runtime: 'claude', model: 'opus', reasoning: 'high',
token: preview.token, planHash: preview.planHash,
};
const confirmed = await post('/api/runtime-profiles', payload);
assert.equal(confirmed.status, 200, await confirmed.clone().text());
const result = await confirmed.json();
assert.deepEqual(
{ runtime: result.profile.runtime, model: result.profile.model, reasoning: result.profile.reasoning },
{ runtime: 'claude', model: 'opus', reasoning: 'high' },
);
assert.equal(result.sessionsStarted, false);
assert.equal(result.existingSessionChanged, false);
const replay = await post('/api/runtime-profiles', payload);
assert.equal(replay.status, 200);
assert.deepEqual(await replay.json(), result);
const verify = openControlPlane({ repositoryRoot: fixtureState.root, env: fixtureState.env });
const event = verify.database.prepare(`
SELECT actor_id, entity_type, entity_id, details FROM audit_events WHERE operation = 'profile.change' ORDER BY rowid DESC LIMIT 1
`).get();
assert.equal(event.actor_id, 'owner');
assert.equal(event.entity_type, 'runtime-profile');
assert.equal(event.entity_id, 'codex-defaults');
assert.equal(JSON.parse(event.details).after.runtime, 'claude');
verify.close();
const html = readFileSync(new URL('../../site/console.html', import.meta.url), 'utf8');
const client = readFileSync(new URL('../../site/console.js', import.meta.url), 'utf8');
assert.match(html, /data-runtime-profile-preview/);
assert.match(html, /data-profile-before/);
assert.match(html, /Running sessions are not changed or restarted/);
assert.match(client, /\/api\/runtime-profiles\/preview/);
assert.match(client, /\/api\/runtime-profiles'/);
});